alda-rb 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/alda-rb/event.rb CHANGED
@@ -40,7 +40,7 @@ class Alda::Event
40
40
  end
41
41
 
42
42
  ##
43
- # Delete itself from its #parent.
43
+ # Delete itself (or its topmost container if it has) from its #parent.
44
44
  # If it is not at its #parent's end, raises Alda::OrderError.
45
45
  #
46
46
  # Here is a list of cases where the method is invoked:
@@ -60,11 +60,40 @@ class Alda::Event
60
60
  # pushed to its #parent.
61
61
  # However, the cases above requires the event be contained
62
62
  # in another object.
63
- def detach_from_parent
64
- if @parent && self != (got = @parent.events.pop)
65
- raise Alda::OrderError.new self, got
63
+ #
64
+ # The parameter +except+ specifies an Array of classes.
65
+ # If #parent is an instance of any of the classes in +except+,
66
+ # the method does nothing.
67
+ def detach_from_parent except = []
68
+ event = self
69
+ event = event.container while event.container
70
+ if @parent && except.none? { @parent.is_a? _1 } && event != (got = @parent.events.pop)
71
+ raise Alda::OrderError.new event, got
66
72
  end
67
73
  end
74
+
75
+ ##
76
+ # :call-seq:
77
+ # is_event_of?(klass) -> true or false
78
+ #
79
+ # Whether it is an event of the given class (+klass+).
80
+ # By default, this is the same as +is_a?(klass)+.
81
+ # It is overridden in Alda::EventContainer.
82
+ def is_event_of? klass
83
+ is_a? klass
84
+ end
85
+
86
+ ##
87
+ # :call-seq:
88
+ # event == other -> true or false
89
+ #
90
+ # Whether it is equal to +other+.
91
+ # To be overriden.
92
+ #
93
+ # Note that #parent and #container should not be taken into account when comparing two events.
94
+ def == other
95
+ super
96
+ end
68
97
  end
69
98
 
70
99
  ##
@@ -83,6 +112,8 @@ class Alda::EventContainer < Alda::Event
83
112
  # p((e/g).event.class) # => Alda::Chord
84
113
  # p((a b).event.class) # => Alda::Sequence
85
114
  # end
115
+ #
116
+ # When setting this attribute, #on_containing is invoked.
86
117
  attr_accessor :event
87
118
 
88
119
  ##
@@ -114,9 +145,11 @@ class Alda::EventContainer < Alda::Event
114
145
  #
115
146
  # +parent+ is the Alda::EventList object containing the event.
116
147
  def initialize event, parent
148
+ super()
117
149
  @event = event
118
- @parent = parent
119
150
  @labels = []
151
+ @count = 1
152
+ self.parent = parent
120
153
  on_containing
121
154
  end
122
155
 
@@ -124,13 +157,31 @@ class Alda::EventContainer < Alda::Event
124
157
  # :call-seq:
125
158
  # container / other -> container
126
159
  #
127
- # Makes #event an Alda::Chord object.
160
+ # If at first #event is not an Alda::Part,
161
+ # makes #event an Alda::Chord object.
128
162
  #
129
163
  # Alda::Score.new { piano_; c/-e/g }.play
130
164
  # # (plays the chord Cm)
131
165
  #
132
- # If the contained event is an Alda::Part object,
166
+ # This usage assumes that +other+ is an Alda::EventContainer and will extract the contained event
167
+ # out from +other+.
168
+ # This will lose some information about +other+, such as #count and #labels,
169
+ # and potentially lead to confusing results.
170
+ #
171
+ # Because the #labels information about +other+ is lost,
172
+ # the label on +d+ disappears in the following example:
173
+ #
174
+ # Alda::Score.new { c/(d%1) }.to_s # => "c/d"
175
+ #
176
+ # The following example shows that the two ways of writing a chord with a label are equivalent:
177
+ # adding the label and then using slash, or using slash and then adding the label.
178
+ # This is because #labels and #count are retained while the #event is updated when #/ is called.
179
+ #
180
+ # Alda::Score.new { p c%1/d == c/d%1 }.to_s # (prints "true") => "c/d'1 c/d'1"
181
+ #
182
+ # If at first #event is an Alda::Part object,
133
183
  # makes #event a new Alda::Part object.
184
+ # The meaning is to play the two parts simultaneously.
134
185
  #
135
186
  # Alda::Score.new { violin_/viola_/cello_; e; f; g}.play
136
187
  # # (plays notes E, F, G with three instruments simultaneously)
@@ -145,12 +196,15 @@ class Alda::EventContainer < Alda::Event
145
196
  self
146
197
  end
147
198
 
199
+ ##
200
+ # :call-seq:
201
+ # to_alda_code() -> String
202
+ #
203
+ # Overrides Alda::Event#to_alda_code.
148
204
  def to_alda_code
149
205
  result = @event.to_alda_code
150
- unless @labels.empty?
151
- result.concat ?', @labels.map(&:to_alda_code).join(?,)
152
- end
153
- result.concat ?*, @count.to_alda_code if @count
206
+ result.concat ?', @labels.map(&:to_alda_code).join(?,) unless @labels.empty?
207
+ result.concat ?*, @count.to_alda_code if @count != 1
154
208
  result
155
209
  end
156
210
 
@@ -163,6 +217,7 @@ class Alda::EventContainer < Alda::Event
163
217
  # For examples, see #%.
164
218
  def * num
165
219
  @count = (@count || 1) * num
220
+ check_in_chord
166
221
  self
167
222
  end
168
223
 
@@ -177,28 +232,86 @@ class Alda::EventContainer < Alda::Event
177
232
  def % labels
178
233
  labels = [labels] unless labels.is_a? Array
179
234
  @labels.replace labels.to_a
235
+ check_in_chord
180
236
  self
181
237
  end
182
238
 
239
+ def event= event # :nodoc:
240
+ @event = event.tap { on_containing }
241
+ end
242
+
183
243
  ##
184
244
  # :call-seq:
185
- # event=(event) -> event
245
+ # check_in_chord() -> true or false
186
246
  #
187
- # Sets #event and invokes #on_containing.
188
- def event= event
189
- @event = event
190
- on_containing
191
- @event
247
+ # This method is called in #%, #*, and #parent=.
248
+ # It checks if #parent is an Alda::Chord and warns about potential dangers.
249
+ # Returns true if there is no danger, and false otherwise.
250
+ #
251
+ # Because \Alda 2 does not support specifying alternative endings inside a chord
252
+ # (something like <tt>a'1/b</tt>)
253
+ # ({alda-lang/alda#383}[https://github.com/alda-lang/alda/issues/383#issuecomment-886084486]),
254
+ # this method will warn about this if such thing happens and we are using \Alda 2.
255
+ #
256
+ # Alda.v2!
257
+ # Alda::Score.new { x{a%1;b} }.to_s # (warns) => "a'1/b"
258
+ #
259
+ # This method will warn about repetitions inside a chord in both generations
260
+ # because the resultant \Alda code is not valid.
261
+ #
262
+ # Alda::Score.new { x{a*2;b} }.to_s # (warns) => "a*2/b"
263
+ def check_in_chord
264
+ if @parent.is_a?(Alda::Event) && @parent.is_event_of?(Alda::Chord)
265
+ Alda::Utils.warn 'alternative endings in chord not allowed in v2' if Alda.v2? && !@labels&.empty?
266
+ Alda::Utils.warn 'repetitions in chord not allowed' if @count && @count != 1
267
+ false
268
+ else
269
+ true
270
+ end
271
+ end
272
+
273
+ ##
274
+ # :call-seq:
275
+ # parent=(event) -> event
276
+ #
277
+ # Overrides Alda::Event#parent=.
278
+ # Sets the Alda::Event#parent of the container as well as that of #event.
279
+ def parent= event
280
+ @parent = event
281
+ check_in_chord
282
+ @event.parent = event
192
283
  end
193
284
 
194
285
  ##
195
286
  # A callback invoked in #event= and ::new.
196
287
  def on_containing
197
- if @event
198
- @event.container = self
199
- @event.parent = @parent
200
- @event.on_contained
201
- end
288
+ return unless @event
289
+ @event.container = self
290
+ @event.parent = @parent
291
+ @event.on_contained
292
+ end
293
+
294
+ ##
295
+ # :call-seq:
296
+ # is_event_of?(klass) -> true or false
297
+ #
298
+ # Overrides Alda::Event#is_event_of?.
299
+ # Whether it is an event of the given class (+klass+)
300
+ # or the contained event is.
301
+ def is_event_of? klass
302
+ super || @event.is_event_of?(klass)
303
+ end
304
+
305
+ ##
306
+ # :call-seq:
307
+ # container == other -> true or false
308
+ #
309
+ # Overrides Alda::Event#==.
310
+ # Returns true if +other+ is an Alda::EventContainer object
311
+ # and #event, #count and #labels are all equal (using <tt>==</tt>).
312
+ def == other
313
+ super || other.is_a?(Alda::EventContainer) &&
314
+ @event == other.event && @count == other.count && @labels == other.labels
202
315
  end
203
316
 
204
317
  ##
@@ -221,15 +334,14 @@ class Alda::EventContainer < Alda::Event
221
334
  # end
222
335
  def method_missing(...)
223
336
  result = @event.__send__(...)
224
- result = self if result == @event
225
- result
337
+ result == @event ? self : result
226
338
  end
227
339
  end
228
340
 
229
341
  ##
230
342
  # An inline lisp event. An Alda::EventContainer containing
231
343
  # an Alda::InlineLisp can be derived using event list
232
- # sugar. See Alda::EventList#method_missing.
344
+ # sugar (see Alda::EventList#method_missing) or by using Alda::EventList#l.
233
345
  #
234
346
  # Sometimes you need help from Alda::LispIdentifier.
235
347
  #
@@ -253,6 +365,9 @@ end
253
365
  # end
254
366
  #
255
367
  # You can operate a score by purely using inline lisp events.
368
+ # The following example only works in Alda 1 due to breaking changes in Alda 2
369
+ # ({alda-lang/alda#483}[https://github.com/alda-lang/alda/issues/483],
370
+ # {alda-lang/alda#484}[https://github.com/alda-lang/alda/issues/484]).
256
371
  #
257
372
  # Alda::Score.new do
258
373
  # part 'piano'
@@ -288,10 +403,11 @@ end
288
403
  #
289
404
  # If you want, you can generate lisp codes using ruby.
290
405
  #
406
+ # Alda.generation = :v1
291
407
  # Alda::Score.new do
292
408
  # println reduce _into_, {}, [{dog: 'food'}, {cat: 'chow'}]
293
409
  # end.save 'temp.clj'
294
- # `clj temp.clj` # => "[[:dog food] [:cat chow]]\n"
410
+ # `clojure temp.clj` # => "{:dog food, :cat chow}\n"
295
411
  class Alda::InlineLisp < Alda::Event
296
412
 
297
413
  ##
@@ -313,18 +429,37 @@ class Alda::InlineLisp < Alda::Event
313
429
  #
314
430
  # The underlines "_" in +head+ will be converted to hyphens "-".
315
431
  def initialize head, *args
316
- @head = head.to_s.gsub ?_, ?-
432
+ super()
433
+ @head = Alda::Utils.snake_to_slug head
317
434
  @args = args
318
435
  end
319
436
 
437
+ ##
438
+ # :call-seq:
439
+ # to_alda_code() -> String
440
+ #
441
+ # Overrides Alda::Event#to_alda_code.
320
442
  def to_alda_code
321
443
  "(#{head} #{args.map(&:to_alda_code).join ' '})"
322
444
  end
323
445
 
446
+ ##
447
+ # See Alda::Event#on_contained.
324
448
  def on_contained
325
449
  super
326
450
  @args.detach_from_parent
327
451
  end
452
+
453
+ ##
454
+ # :call-seq:
455
+ # inline_lisp == other -> true or false
456
+ #
457
+ # Overrides Alda::Event#==.
458
+ # Returns true if +other+ is an Alda::InlineLisp
459
+ # and has the same #head and #args as +inline_lisp+ (using <tt>==</tt>).
460
+ def == other
461
+ super || other.is_a?(Alda::InlineLisp) && @head == other.head && @args == other.args
462
+ end
328
463
  end
329
464
 
330
465
  ##
@@ -373,6 +508,7 @@ class Alda::Note < Alda::Event
373
508
  # slur if 2,
374
509
  # both natural and slur if 3.
375
510
  def initialize pitch, duration
511
+ super()
376
512
  @pitch = pitch.to_s
377
513
  @duration = duration.to_s.tr ?_, ?~
378
514
  case @duration[-1]
@@ -431,11 +567,27 @@ class Alda::Note < Alda::Event
431
567
  self
432
568
  end
433
569
 
570
+ ##
571
+ # :call-seq:
572
+ # to_alda_code() -> String
573
+ #
574
+ # Overrides Alda::Event#to_alda_code.
434
575
  def to_alda_code
435
576
  result = @pitch + @duration
436
577
  result.concat ?*, @count.to_alda_code if @count
437
578
  result
438
579
  end
580
+
581
+ ##
582
+ # :call-seq:
583
+ # note == other -> true or false
584
+ #
585
+ # Overrides Alda::Event#==.
586
+ # Returns true if +other+ is an Alda::Note
587
+ # and has the same #pitch and #duration as +note+ (using <tt>==</tt>).
588
+ def == other
589
+ super || other.is_a?(Alda::Note) && @pitch == other.pitch && @duration == other.duration
590
+ end
439
591
  end
440
592
 
441
593
  ##
@@ -463,12 +615,29 @@ class Alda::Rest < Alda::Event
463
615
  #
464
616
  # Underlines "_" in +duration+ will be converted to tildes "~".
465
617
  def initialize duration
618
+ super()
466
619
  @duration = duration.to_s.tr ?_, ?~
467
620
  end
468
621
 
622
+ ##
623
+ # :call-seq:
624
+ # to_alda_code() -> String
625
+ #
626
+ # Overrides Alda::Event#to_alda_code.
469
627
  def to_alda_code
470
628
  ?r + @duration
471
629
  end
630
+
631
+ ##
632
+ # :call-seq:
633
+ # rest == other -> true or false
634
+ #
635
+ # Overrides Alda::Event#==.
636
+ # Returns true if +other+ is an Alda::Rest
637
+ # and has the same #duration as +rest+ (using <tt>==</tt>).
638
+ def == other
639
+ super || other.is_a?(Alda::Rest) && @duration == other.duration
640
+ end
472
641
  end
473
642
 
474
643
  ##
@@ -501,6 +670,7 @@ class Alda::Octave < Alda::Event
501
670
  #
502
671
  # Creates an Alda::Octave.
503
672
  def initialize num
673
+ super()
504
674
  @num = num.to_s
505
675
  @up_or_down = 0
506
676
  end
@@ -531,6 +701,11 @@ class Alda::Octave < Alda::Event
531
701
  self
532
702
  end
533
703
 
704
+ ##
705
+ # :call-seq:
706
+ # to_alda_code() -> String
707
+ #
708
+ # Overrides Alda::Event#to_alda_code.
534
709
  def to_alda_code
535
710
  case @up_or_down <=> 0
536
711
  when 0
@@ -541,6 +716,17 @@ class Alda::Octave < Alda::Event
541
716
  ?< * -@up_or_down
542
717
  end
543
718
  end
719
+
720
+ ##
721
+ # :call-seq:
722
+ # octave == other -> true or false
723
+ #
724
+ # Overrides Alda::Event#==.
725
+ # Returns true if +other+ is an Alda::Octave
726
+ # and has the same #num and #up_or_down as +octave+ (using <tt>==</tt>).
727
+ def == other
728
+ super || other.is_a?(Alda::Octave) && @num == other.num && @up_or_down == other.up_or_down
729
+ end
544
730
  end
545
731
 
546
732
  ##
@@ -574,12 +760,39 @@ class Alda::Chord < Alda::Event
574
760
  # Alda::Score.new { piano_; x { c; -e; g } }.play
575
761
  # # (plays chord Cm)
576
762
  def initialize *events, &block
763
+ events.each { _1.parent = self if _1.is_a? Alda::Event }
577
764
  @events = events
578
765
  super &block
579
766
  end
580
767
 
768
+ ##
769
+ # :call-seq:
770
+ # to_alda_code() -> String
771
+ #
772
+ # Overrides Alda::Event#to_alda_code.
773
+ #
774
+ # Behaves differently for \Alda 1 and \Alda 2:
775
+ # because \Alda 2 does not allow octave changes as part of a chord
776
+ # (something like <tt>a/>/c</tt>, and we have to write <tt>a>/c</tt> or <tt>a/>c</tt> instead)
777
+ # ({alda-lang/alda#383}[https://github.com/alda-lang/alda/issues/383]),
778
+ # the code generated by this method will omit the slash before an octave change.
779
+ #
780
+ # Alda.generation = :v1
781
+ # Alda::Score.new { a/o!/c; a/o5/c }.to_s # => "a/>/c a/o5/c"
782
+ # Alda.generation = :v2
783
+ # Alda::Score.new { a/o!/c; a/o5/c }.to_s # => "a>/c a o5/c"
581
784
  def to_alda_code
582
- events_alda_codes ?/
785
+ return events_alda_codes ?/ if Alda.v1?
786
+ @events.each_with_index.with_object '' do |(event, i), result|
787
+ if i == 0
788
+ # concat nothing
789
+ elsif event.is_event_of? Alda::Octave
790
+ result.concat ' ' unless event.num.empty?
791
+ else
792
+ result.concat '/'
793
+ end
794
+ result.concat event.to_alda_code
795
+ end
583
796
  end
584
797
  end
585
798
 
@@ -631,10 +844,16 @@ class Alda::Part < Alda::Event
631
844
  #
632
845
  # Creates an Alda::Part.
633
846
  def initialize names, arg = nil
634
- @names = names.map { |name| name.to_s.tr ?_, ?- }
847
+ super()
848
+ @names = names.map { Alda::Utils.snake_to_slug _1 }
635
849
  @arg = arg
636
850
  end
637
851
 
852
+ ##
853
+ # :call-seq:
854
+ # to_alda_code() -> String
855
+ #
856
+ # Overrides Alda::Event#to_alda_code.
638
857
  def to_alda_code
639
858
  result = @names.join ?/
640
859
  result.concat " \"#{@arg}\"" if @arg
@@ -657,17 +876,26 @@ class Alda::Part < Alda::Event
657
876
  str[-1] = ''
658
877
  @names.last.concat ?., str
659
878
  if args.size == 1
660
- unless @container
661
- @container = Alda::EventContainer.new nil, @parent
662
- @parent.events.delete self
663
- @parent.push @container
664
- end
665
- @container.event = Alda::Sequence.join self, args.first.tap(&:detach_from_parent)
666
- @container
879
+ arg = args.first.tap &:detach_from_parent
880
+ detach_from_parent
881
+ container = Alda::EventContainer.new Alda::Sequence.join(self, arg), @parent
882
+ @parent.events.push container
883
+ container
667
884
  else
668
885
  @container || self
669
886
  end
670
887
  end
888
+
889
+ ##
890
+ # :call-seq:
891
+ # part == other -> true or false
892
+ #
893
+ # Overrides Alda::Event#==.
894
+ # Returns true if +other+ is an Alda::Part
895
+ # and has the same #names and #arg as +part+ (using <tt>==</tt>).
896
+ def == other
897
+ super || other.is_a?(Alda::Part) && @names == other.names && @arg == other.arg
898
+ end
671
899
  end
672
900
 
673
901
  ##
@@ -690,12 +918,29 @@ class Alda::Voice < Alda::Event
690
918
  #
691
919
  # Creates an Alda::Voice.
692
920
  def initialize num
921
+ super()
693
922
  @num = num
694
923
  end
695
924
 
925
+ ##
926
+ # :call-seq:
927
+ # to_alda_code() -> String
928
+ #
929
+ # Overrides Alda::Event#to_alda_code.
696
930
  def to_alda_code
697
931
  ?V + num + ?:
698
932
  end
933
+
934
+ ##
935
+ # :call-seq:
936
+ # voice == other -> true or false
937
+ #
938
+ # Overrides Alda::Event#==.
939
+ # Returns true if +other+ is an Alda::Voice
940
+ # and has the same #num as +voice+ (using <tt>==</tt>).
941
+ def == other
942
+ super || other.is_a?(Alda::Voice) && @num == other.num
943
+ end
699
944
  end
700
945
 
701
946
  ##
@@ -731,9 +976,25 @@ class Alda::Cram < Alda::Event
731
976
  super &block
732
977
  end
733
978
 
979
+ ##
980
+ # :call-seq:
981
+ # to_alda_code() -> String
982
+ #
983
+ # Overrides Alda::Event#to_alda_code.
734
984
  def to_alda_code
735
985
  "{#{events_alda_codes}}#@duration"
736
986
  end
987
+
988
+ ##
989
+ # :call-seq:
990
+ # cram == other -> true or false
991
+ #
992
+ # Overrides Alda::EventList#==.
993
+ # Returns true if the super method returns true and +other+
994
+ # has the same #duration as +cram+ (using <tt>==</tt>).
995
+ def == other
996
+ super && @duration == other.duration
997
+ end
737
998
  end
738
999
 
739
1000
  ##
@@ -760,12 +1021,29 @@ class Alda::Marker < Alda::Event
760
1021
  #
761
1022
  # Underlines in +name+ is converted to hyphens.
762
1023
  def initialize name
763
- @name = name.to_s.tr ?_, ?-
1024
+ super()
1025
+ @name = Alda::Utils.snake_to_slug name
764
1026
  end
765
1027
 
1028
+ ##
1029
+ # :call-seq:
1030
+ # to_alda_code() -> String
1031
+ #
1032
+ # Overrides Alda::Event#to_alda_code.
766
1033
  def to_alda_code
767
1034
  ?% + @name
768
1035
  end
1036
+
1037
+ ##
1038
+ # :call-seq:
1039
+ # marker == other -> true or false
1040
+ #
1041
+ # Overrides Alda::Event#==.
1042
+ # Returns true if +other+ is an Alda::Marker
1043
+ # and has the same #name as +marker+ (using <tt>==</tt>).
1044
+ def == other
1045
+ super || other.is_a?(Alda::Marker) && @name == other.name
1046
+ end
769
1047
  end
770
1048
 
771
1049
  ##
@@ -789,12 +1067,29 @@ class Alda::AtMarker < Alda::Event
789
1067
  #
790
1068
  # Underlines "_" in +name+ is converted to hyphens "-".
791
1069
  def initialize name
792
- @name = name.to_s.tr ?_, ?-
1070
+ super()
1071
+ @name = Alda::Utils.snake_to_slug name
793
1072
  end
794
1073
 
1074
+ ##
1075
+ # :call-seq:
1076
+ # to_alda_code() -> String
1077
+ #
1078
+ # Overrides Alda::Event#to_alda_code.
795
1079
  def to_alda_code
796
1080
  ?@ + @name
797
1081
  end
1082
+
1083
+ ##
1084
+ # :call-seq:
1085
+ # at_marker == other -> true or false
1086
+ #
1087
+ # Overrides Alda::Event#==.
1088
+ # Returns true if +other+ is an Alda::AtMarker
1089
+ # and has the same #name as +at_marker+ (using <tt>==</tt>).
1090
+ def == other
1091
+ super || other.is_a?(Alda::AtMarker) && @name == other.name
1092
+ end
798
1093
  end
799
1094
 
800
1095
  ##
@@ -814,7 +1109,8 @@ end
814
1109
  # p((c d e f).event.class) # => Alda::Sequence
815
1110
  # end
816
1111
  #
817
- # The effects of the two examples above are the same.
1112
+ # The effects of the two examples above are technically the same
1113
+ # although actually the generated list of events are slightly different.
818
1114
  class Alda::Sequence < Alda::Event
819
1115
  include Alda::EventList
820
1116
 
@@ -829,6 +1125,8 @@ class Alda::Sequence < Alda::Event
829
1125
  # [a].flatten # => [#<Object:...>]
830
1126
  module RefineFlatten
831
1127
  refine Array do
1128
+ ##
1129
+ # Overrides Array#flatten.
832
1130
  def flatten
833
1131
  each_with_object [] do |element, result|
834
1132
  if element.is_a? Array
@@ -842,8 +1140,13 @@ class Alda::Sequence < Alda::Event
842
1140
  end
843
1141
  using RefineFlatten
844
1142
 
1143
+ ##
1144
+ # :call-seq:
1145
+ # to_alda_code() -> String
1146
+ #
1147
+ # Overrides Alda::Event#to_alda_code.
845
1148
  def to_alda_code
846
- @events.to_alda_code
1149
+ "[#{events_alda_codes}]"
847
1150
  end
848
1151
 
849
1152
  ##
@@ -857,7 +1160,7 @@ class Alda::Sequence < Alda::Event
857
1160
  def self.join *events
858
1161
  new do
859
1162
  @events = events.map do |event|
860
- while event.is_a?(Alda::EventContainer) && !event.count && event.labels.empty?
1163
+ while event.is_a?(Alda::EventContainer) && event.count == 1 && event.labels.empty?
861
1164
  event = event.event
862
1165
  end
863
1166
  event.is_a?(Alda::Sequence) ? event.events : event
@@ -894,10 +1197,6 @@ class Alda::SetVariable < Alda::Event
894
1197
  # The name of the variable.
895
1198
  attr_accessor :name
896
1199
 
897
- ##
898
- # The events passed to it using arguments instead of a block.
899
- attr_reader :original_events
900
-
901
1200
  ##
902
1201
  # :call-seq:
903
1202
  # new(name, *events, &block) -> Alda::SetVariable
@@ -905,21 +1204,38 @@ class Alda::SetVariable < Alda::Event
905
1204
  # Creates an Alda::SetVariable.
906
1205
  def initialize name, *events, &block
907
1206
  @name = name.to_sym
908
- @original_events = events
909
- @events = events.clone
1207
+ @events = events
910
1208
  super &block
911
1209
  end
912
1210
 
913
1211
  ##
1212
+ # :call-seq:
1213
+ # to_alda_code() -> String
1214
+ #
914
1215
  # Specially, the returned value ends with a newline "\\n".
1216
+ # Overrides Alda::Event#to_alda_code.
915
1217
  def to_alda_code
916
1218
  "#@name = #{events_alda_codes}\n"
917
1219
  end
918
1220
 
1221
+ ##
1222
+ # See Alda::Event#on_contained.
919
1223
  def on_contained
920
1224
  super
921
1225
  @parent.variables.add @name
922
- @original_events.detach_from_parent
1226
+ @events.detach_from_parent [self.class]
1227
+ @events.each { _1.parent = self if _1.is_a? Alda::Event }
1228
+ end
1229
+
1230
+ ##
1231
+ # :call-seq:
1232
+ # set_variable == other -> true or false
1233
+ #
1234
+ # Overrides Alda::EventList#==.
1235
+ # Returns true if the super method returns true and +other+
1236
+ # has the same #name as +set_variable+ (using <tt>==</tt>).
1237
+ def == other
1238
+ super && @name == other.name
923
1239
  end
924
1240
  end
925
1241
 
@@ -942,12 +1258,29 @@ class Alda::GetVariable < Alda::Event
942
1258
  #
943
1259
  # Creates an Alda::GetVariable.
944
1260
  def initialize name
1261
+ super()
945
1262
  @name = name
946
1263
  end
947
1264
 
1265
+ ##
1266
+ # :call-seq:
1267
+ # to_alda_code() -> String
1268
+ #
1269
+ # Overrides Alda::Event#to_alda_code.
948
1270
  def to_alda_code
949
1271
  @name.to_s
950
1272
  end
1273
+
1274
+ ##
1275
+ # :call-seq:
1276
+ # get_variable == other -> true or false
1277
+ #
1278
+ # Overrides Alda::Event#==.
1279
+ # Returns true if +other+ is an Alda::GetVariable
1280
+ # and has the same #name as +get_variable+ (using <tt>==</tt>).
1281
+ def == other
1282
+ super || other.is_a?(Alda::GetVariable) && @name == other.name
1283
+ end
951
1284
  end
952
1285
 
953
1286
  ##
@@ -974,10 +1307,69 @@ class Alda::LispIdentifier < Alda::Event
974
1307
  #
975
1308
  # Underlines "_" in +name+ is converted to hyphens "-".
976
1309
  def initialize name
977
- @name = name.tr ?_, ?-
1310
+ super()
1311
+ @name = Alda::Utils.snake_to_slug name
978
1312
  end
979
1313
 
1314
+ ##
1315
+ # :call-seq:
1316
+ # to_alda_code() -> String
1317
+ #
1318
+ # Overrides Alda::Event#to_alda_code.
980
1319
  def to_alda_code
981
1320
  @name
982
1321
  end
1322
+
1323
+ ##
1324
+ # :call-seq:
1325
+ # lisp_identifier == other -> true or false
1326
+ #
1327
+ # Overrides Alda::Event#==.
1328
+ # Returns true if +other+ is an Alda::LispIdentifier
1329
+ # and has the same #name as +lisp_identifier+ (using <tt>==</tt>).
1330
+ def == other
1331
+ super || other.is_a?(Alda::LispIdentifier) && @name == other.name
1332
+ end
1333
+ end
1334
+
1335
+ ##
1336
+ # A special event that contains raw \Alda codes.
1337
+ # This is a walkaround for the absence of <tt>alda-code</tt> function in \Alda 2
1338
+ # ({alda-lang/alda#379}[https://github.com/alda-lang/alda/issues/379]).
1339
+ # You can use Alda::EventList#raw to add an Alda::Raw event to the event list.
1340
+ class Alda::Raw < Alda::Event
1341
+
1342
+ ##
1343
+ # The raw \Alda codes.
1344
+ attr_accessor :contents
1345
+
1346
+ ##
1347
+ # :call-seq:
1348
+ # new(code) -> Alda::Raw
1349
+ #
1350
+ # Creates an Alda::Raw.
1351
+ def initialize contents
1352
+ super()
1353
+ @contents = contents
1354
+ end
1355
+
1356
+ ##
1357
+ # :call-seq:
1358
+ # to_alda_code() -> String
1359
+ #
1360
+ # Overrides Alda::Event#to_alda_code.
1361
+ def to_alda_code
1362
+ @contents
1363
+ end
1364
+
1365
+ ##
1366
+ # :call-seq:
1367
+ # raw == other -> true or false
1368
+ #
1369
+ # Overrides Alda::Event#==.
1370
+ # Returns true if +other+ is an Alda::Raw
1371
+ # and has the same #contents as +raw+ (using <tt>==</tt>).
1372
+ def == other
1373
+ super || other.is_a?(Alda::Raw) && @contents == other.contents
1374
+ end
983
1375
  end