alda-rb 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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