简体   繁体   中英

What are the uses of the '<<' operator in ruby

I have this sample code, which is essentially just a few basic classes for working with mdii files

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

most of it makes perfect sense to me except for the lines that use the << operator, from all of my research the only reason to use a << is when your defining a class that will be a singleton. So in what way specifically is the << being used in this code?

From https://github.com/jimm/midilib :
MIDI::Track is a track that contains an array of events.

So with << you're adding events to your track. It is the same as melody.events.push(MIDI::NoteOnEvent.new(0, midi_note, 127, 0))

<< could also be used for bit shifting operations

http://calleerlandsson.com/2014/02/06/rubys-bitwise-operators/

<< operator may be used either for bitwise operations (quite unlikely here) or may be overloaded inside the class to match some behavior. In this case there is (probably) an Array object and thus the event is pushed into the @events array via this operator. More info about this use case can be found here .

Take notice, that in future you can bump into other situations where this operator is used and not everytime it will mean same thing - it depends on library creator. The other use case that comes into mind right now can be ActiveRecord Relationships, as has_many where also you can use this operator to immediately push an object to relationship and save. More info about this one can be found in api docs here . Quick sample:

class User < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
end

And then somewhere in code you can use:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM