2015-05-09 74 views
0

我有此示例代码,它本质上只是一些基本课程与mdii文件什么是“<<”操作符的使用红宝石

class Array 
    def to_midi(file, note_length='eighth') 

     midi_max = 108.0 
     midi_min = 21.0 

     low, high = min, max 
     song = MIDI::Sequence.new 

     # Create a new track to hold the melody, running at 120 beats per minute. 
     song.tracks << (melody = MIDI::Track.new(song)) 
     melody.events << MIDI::Tempo.new(MIDI::Tempo.bpm_to_mpq(120)) 

     # Tell channel zero to use the "piano" sound. 
     melody.events << MIDI::ProgramChange.new(0, 0) 

     # Create a series of note events that play on channel zero. 
     each do |number| 
      midi_note = (midi_min + ((number-midi_min) * (midi_max-low)/high)).to_i 
      melody.events << MIDI::NoteOnEvent.new(0, midi_note, 127, 0) 
      melody.events << MIDI::NoteOffEvent.new(0, midi_note, 127, 
      song.note_to_delta(note_length)) 
     end 

     open(file, 'w') { |f| song.write(f) } 
    end 
end 
class TimedTrack < MIDI::Track 
    MIDDLE_C = 60 
    @@channel_counter=0 

    def initialize(number, song) 
     super(number) 
     @sequence = song 
     @time = 0 
     @channel = @@channel_counter 
     @@channel_counter += 1 
    end 

    # Tell this track's channel to use the given instrument, and 
    # also set the track's instrument display name. 
    def instrument=(instrument) 
     @events << MIDI::ProgramChange.new(@channel, instrument) 
     super(MIDI::GM_PATCH_NAMES[instrument]) 
    end 

     # Add one or more notes to sound simultaneously. Increments the per-track 
     # timer so that subsequent notes will sound after this one finishes. 
    def add_notes(offsets, velocity=127, duration='quarter') 
     offsets = [offsets] unless offsets.respond_to? :each 
     offsets.each do |offset| 
      event(MIDI::NoteOnEvent.new(@channel, MIDDLE_C + offset, velocity)) 
     end 
     @time += @sequence.note_to_delta(duration) 
     offsets.each do |offset| 
      event(MIDI::NoteOffEvent.new(@channel, MIDDLE_C + offset, velocity)) 
     end 
     recalc_delta_from_times 
    end 

     # Uses add_notes to sound a chord (a major triad in root position), using the 
     # given note as the low note. Like add_notes, increments the per-track timer. 
    def add_major_triad(low_note, velocity=127, duration='quarter') 
     add_notes([0, 4, 7].collect { |x| x + low_note }, velocity, duration) 
    end 

    private 

     def event(event) 
      @events << event 
      event.time_from_start = @time 
     end 
end 

工作大部分是让我感觉良好除了使用<<算子的行外,从我的所有研究中,使用<<的唯一原因是当您定义一个将是单例的类时。那么在这个代码中使用<<的具体方式是什么?

回答

0

<<操作者可以使用1对位运算(此处不太可能),或者可以在类中被重载以匹配一些行为。在这种情况下,(可能)有一个Array对象,因此event通过此运算符被推入@events数组中。有关此用例的更多信息can be found here

请注意,将来您可能会遇到使用此操作符的其他情况,而不是每次都意味着相同的事情 - 这取决于库创建者。现在想到的另一个用例可以是ActiveRecord Relationships,如has_many,您也可以使用此运算符立即将对象推送到关系并保存。关于这个的更多信息可以在api docs here找到。快速样品:

class User < ActiveRecord::Base 
    has_many :posts 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
end 

然后在某处代码,你可以使用:

@post = Post.find(10) 
@user = User.find(1) 
@user.posts << @post 
# automatically save the @post object with updated foreign key 
+0

谢谢!非常好的格式和丰富的答案! –