Monday, December 19, 2011

named_value_class 0.7 released

rubygems.org page
repo page on github.com

First a complete example:

require 'named_value_class'

NamedValueClass Pitch:Fixnumconstrain:0..11 do
  minus_a :Interval do |lhs,minus,rhs|
    result = minus.call(rhs) % 12
    is_sharp? ? Pitch.sharps[result] : Pitch.flats[result]
  end
  
  all_operators_with_a :Pitchraise:SyntaxError
  
  def as_flat
    self.class.naturals[self|| self.class.flats[self]
  end
  
  def as_sharp
    self.class.naturals[self|| self.class.sharps[self]
  end
end

Pitch Bs:  0,   sharp:true  
Pitch C:   0, natural:true 
Pitch Cs:  1,   sharp:true 
Pitch Db:  1,    flat:true 
Pitch D:   2, natural:true 
Pitch Ds:  3,   sharp:true 
Pitch Eb:  3,    flat:true 
Pitch E:   4, natural:true 
Pitch Fb:  4,    flat:true 
Pitch Es:  5,   sharp:true 
Pitch F:   5, natural:true 
Pitch Fs:  6,   sharp:true 
Pitch Gb:  6,    flat:true 
Pitch G:   7, natural:true 
Pitch Gs:  8,   sharp:true 
Pitch Ab:  8,    flat:true 
Pitch A:   9, natural:true 
Pitch As: 10,   sharp:true 
Pitch Bb: 10,    flat:true 
Pitch B:  11, natural:true 
Pitch Cb: 11,    flat:true 

What does this do?

First create a new class named Pitch that delegates most work to Fixnum with a value between 0 and 11 inclusive; Open a block to define some specialized methods:

NamedValueClass Pitch:Fixnumconstrain:0..11 do

Define how to handle the "Pitch - Interval" use case:

  minus_a :Interval do |lhs,minus,rhs|

When defining operators the blocks are always yieled: the LHS (left hand side), a proc with the original, default implementation of the operator you are redefining, and the RHS.  The passed proc's receiver is the LHS so in the following code "minus.call(rhs)" performs "lhs - rhs".

    result = minus.call(rhs) % 12

Since we plan on setting boolean parameters named 'sharp' and 'flat' when we define Pitch constants later we can use methods is_sharp?, is_flat?, Pitch.sharps(value) and Pitch.flats(value):

    is_sharp? ? Pitch.sharps[result] : Pitch.flats[result]

It doesn't make any sense to do math with a Pitch on the left and right sides so all operators should raise a SyntaxError.  Example: Ds + C

  all_operators_with_a :Pitchraise:SyntaxError

Define some instance methods:  
  def as_flat
    self.class.naturals[self|| self.class.flats[self]
  end
  
  def as_sharp
    self.class.naturals[self|| self.class.sharps[self]
  end

Now create Pitch constants:

Pitch Bs:  0,   sharp:true  
Pitch C:   0, natural:true 
Pitch Cs:  1,   sharp:true 
Pitch Db:  1,    flat:true 
Pitch D:   2, natural:true 
Pitch Ds:  3,   sharp:true 
Pitch Eb:  3,    flat:true 
Pitch E:   4, natural:true 
Pitch Fb:  4,    flat:true 
Pitch Es:  5,   sharp:true 
Pitch F:   5, natural:true 
Pitch Fs:  6,   sharp:true 
Pitch Gb:  6,    flat:true 
Pitch G:   7, natural:true 
Pitch Gs:  8,   sharp:true 
Pitch Ab:  8,    flat:true 
Pitch A:   9, natural:true 
Pitch As: 10,   sharp:true 
Pitch Bb: 10,    flat:true 
Pitch B:  11, natural:true 
Pitch Cb: 11,    flat:true 

An irb session with the above code loaded:

>> load './pitch_class.rb' #=> true
>> include Pitch::NamedValues #=> Object
>> C #=> C
>> Eb #=> Eb
>> [C,Eb] #=> [C, Eb]
>> C > Eb #=> false
>> C.value #=> 0
>> Eb.value #=> 3
>> C + 2 #=> D
>> Db + 7 #=> Gs
>> Db.is_sharp? #=> nil
>> Db.is_natural? #=> nil
>> Db.is_flat? #=> true
>> Db.is_insane?
NoMethodError: undefined method `is_insane?' for Db:Kernel::Pitch
>> Pitch H:0, insane:true #=> H
>> Db.is_insane? #=> nil                                                                                                                                                                                 
>> H.is_insane? #=> true
>> Pitch.flats #=> {1=>Db, 3=>Eb, 4=>Fb, 6=>Gb, 8=>Ab, 10=>Bb, 11=>Cb}

rubygems.org page
repo page on github.com


1 comment:

  1. now that this is "done" i can get back to peas. 0.3 should be out by tomorrow.

    ReplyDelete