Class: Request::Choregraphy

Inherits:
Base::Event show all
Defined in:
lib/violet/request.rb

Overview

Choregraphy

Choregraphy in the Violet API looks like binary CSV code. It isn’t really “user-friendly”. We use a DSL (Domain Specific Language) to describe Choregraphy more easily, and then translate it in with this class. This allows us to create a more powerful language, making easy (for examples) to set all leds in one sentence, instead of five 90% redundant lines :

‘set all to green’ will we translated into ‘chor=10,0,led,0,0,255,0,0,led,1,0,255,0,0,led,2,0,255,0,0,led,3,0,255,0,0,led,4,0,255,0’

Moreover, if you think that a Choregraphy is a Set of Events (that are either an ear command either a led command), then we can use logic operations such as ==, +, -, | and & on Choregraphy (code taken from test file test_request_chor.rb):

one     = Choregraphy.new { move left ear forward of degrees 42 }
two     = Choregraphy.new { move right ear forward of degrees 42 }
onetwo  = Choregraphy.new { move both ears forward of degrees 42 }

assert_equal one | two, one + two
assert_equal one & two, Choregraphy.new
assert_equal one - two, one
assert_equal two - one, two
assert_equal onetwo, one + two
assert_equal onetwo & two, two
assert_equal onetwo & one, one
assert_equal onetwo - two, one
assert_equal onetwo - one, two
assert_equal onetwo | two, onetwo
assert_equal onetwo | one, onetwo

Choregraphy Creation

see new

Choregraphy DSL description

Here is the syntax description: [] are alternation with | or range with - and <> are optionals.

at time 1.2 <do>
    move [right|left|both] <ear|ears> [backward|forward] <of> degrees [0-180]
    set [bottom|left|middle|right|top|all] <led|leds> to [off|red|green|blue|yellow|magenta|cyan|white|rgb([0-255],[0-255],[0-255])]
<end>

Examples

for examples, please see the test file (namely test_request_chor.rb), because there are a lot of possible chor description and I don’t want to duplicate too much code :)

Defined Under Namespace

Modules: Ears, Leds Classes: BadChorDesc, EarCommandStruct, LedCommandStruct

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base::Event

#+, #streamed?

Constructor Details

#initialize(h = Hash.new, &block) ⇒ Choregraphy

Take some Choregraphy DSL code and translate it into a Choregraphy description of Violet API.

Arguments

(optionals) an Hash in argument with keys:

name

the chortitle

code

an array of String/Proc or a String/Proc that describe the Choregraphy in our DSL.

(optionals) a block of code that describe the Choregraphy.

Raise

raise a Choregraphy::BadChorDesc if not happy.

Examples (all results are equals)

Request::Choregraphy.new { set all off; move right ear forward of degrees 180 } #   => #<Request::Choregraphy:0x2b07a05f8ca0 @chor=["0,led,0,0,0,0", "0,led,1,0,0,0", "0,led,2,0,0,0", "0,led,3,0,0,0", "0,led,4,0,0,0", "0,motor,0,180,0,0"], @code=[#<Proc:0x00002b07a05f8d40@(irb):3>], @time=0>
Request::Choregraphy.new :code => 'set all off; move right ear forward of degrees 180' #   => #<Request::Choregraphy:0x2b07a05e84b8 @chor=["0,led,0,0,0,0", "0,led,1,0,0,0", "0,led,2,0,0,0", "0,led,3,0,0,0", "0,led,4,0,0,0", "0,motor,0,180,0,0"], @code=["set all off; move right ear forward of degrees 180"], @time=0>
Request::Choregraphy.new :code => [ 'set all off', 'move right ear forward of degrees 180' ] #   => #<Request::Choregraphy:0x2b07a05dae30 @chor=["0,led,0,0,0,0", "0,led,1,0,0,0", "0,led,2,0,0,0", "0,led,3,0,0,0", "0,led,4,0,0,0", "0,motor,0,180,0,0"], @code=["set all off", "move right ear forward of degrees 180"], @time=0>


363
364
365
366
367
368
# File 'lib/violet/request.rb', line 363

def initialize(h=Hash.new, &block)
  @name = h[:name] if h[:name]
  @code = if block_given? then block else h[:code] end
  __choreval__
  @chor.sort! unless @chor.nil?
end

Class Method Details

.bubble(*methods) ⇒ Object

define dummy methods for DSL



380
381
382
383
384
385
# File 'lib/violet/request.rb', line 380

def self.bubble(*methods)
  methods.each do |m|
    define_method(m) { |args| args }
    private(m.to_sym)
  end
end

Instance Method Details

#==(other) ⇒ Object



400
401
402
# File 'lib/violet/request.rb', line 400

def == other
  self.chor == other.chor
end

#move(command) ⇒ Object

Raises:



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/violet/request.rb', line 438

def move command
  raise BadChorDesc.new('wrong Choregraphy description')    unless command.is_a?(EarCommandStruct)
  raise BadChorDesc.new('need a time')                      unless command.time
  raise BadChorDesc.new('time must be >= zero')             unless command.time.to_i >= 0
  raise BadChorDesc.new('need an angle')                    unless command.angle
  raise BadChorDesc.new('angle must be between 0 and 180')  unless (0..180).include?(command.angle)
  raise BadChorDesc.new('need a direction')                 unless command.direction
  raise BadChorDesc.new('wrong direction')                  unless command.direction.between?(Ears::Directions::FORWARD,Ears::Directions::BACKWARD)
  raise BadChorDesc.new('need an element')                  unless command.element
  raise BadChorDesc.new('wrong element')                    unless command.element == :both or command.element.between?(Ears::Positions::RIGHT,Ears::Positions::LEFT)

  template = '%s,motor,%s,%s,0,%s'

  if command.element == :both
    # we don't know, maybe your rabbit has more than two ears :)
    (Ears::Positions.constants - ['BOTH']).each do |cste_name|
      cste = Helpers.constantize "#{self.class}::Ears::Positions::#{cste_name}"
      @chor << template % [ command.time.to_i, cste,  command.angle, command.direction ]
    end
  else
    @chor << template % [ command.time.to_i,  command.element, command.angle, command.direction ]
  end
end

#set(command) ⇒ Object

Raises:



404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/violet/request.rb', line 404

def set command
  raise BadChorDesc.new('wrong Choregraphy description')    unless command.is_a?(LedCommandStruct)
  raise BadChorDesc.new('need an element')                  unless command.elements
  command.elements.each do |e|
    raise BadChorDesc.new('wrong element')                  unless e == :all or e.between?(Leds::Positions::BOTTOM,Leds::Positions::TOP)
  end
  raise BadChorDesc.new('need a time')                      unless command.time
  raise BadChorDesc.new('time must be >= than zero')        unless command.time.to_i >= 0
  raise BadChorDesc.new('need a color')                     unless command.color
  raise BadChorDesc.new('wrong size for rgb color array')   unless command.color.size == 3
  command.color.collect! do |c|
    raise BadChorDesc.new('color code must be betwen 0 and 255') unless c.to_i.between?(0,255)
    c.to_i
  end

  template = '%s,led,%s,%s'
  command.color = command.color.join(',')

  # remove trailling element if all is set
  command.elements.uniq!
  command.elements = [:all] if command.elements.include?(:all)

  command.elements.each do |e|
    if e == :all
      (Leds::Positions.constants - ['ALL']).each do |cste_name|
        cste = Helpers.constantize "#{self.class}::Leds::Positions::#{cste_name}"
        @chor << template % [ command.time.to_i, cste, command.color ]
      end
    else
        @chor << template % [ command.time.to_i,  e, command.color ]
    end
  end
end

#to_urlObject

Raises:



370
371
372
373
374
375
376
377
# File 'lib/violet/request.rb', line 370

def to_url
  raise BadChorDesc.new('no choregraphy given') unless @chor

  url = Array.new
  url << "chor=10," + @chor.join(',') unless @chor.nil?
  url << "chortitle=#{@name}" unless @name.nil?
  url
end