alda-rb 0.2.1 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +18 -0
- data/.gitignore +2 -2
- data/CHANGELOG.md +271 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +54 -0
- data/README.md +56 -7
- data/Rakefile +2 -2
- data/alda-rb.gemspec +3 -3
- data/examples/bwv846_prelude.rb +3 -3
- data/examples/clapping_music.rb +1 -1
- data/examples/dot_accessor.rb +1 -1
- data/examples/dynamics.rb +22 -0
- data/examples/entropy.rb +2 -2
- data/examples/hanon.rb +2 -2
- data/examples/marriage_d_amour.rb +114 -0
- data/examples/multi_poly.rb +2 -2
- data/examples/track-volume.rb +32 -0
- data/examples/variables-2.rb +16 -0
- data/exe/alda-irb +29 -0
- data/lib/alda-rb/commandline.rb +139 -33
- data/lib/alda-rb/error.rb +82 -9
- data/lib/alda-rb/event.rb +441 -49
- data/lib/alda-rb/event_list.rb +54 -7
- data/lib/alda-rb/patches.rb +88 -14
- data/lib/alda-rb/repl.rb +311 -59
- data/lib/alda-rb/utils.rb +47 -0
- data/lib/alda-rb/version.rb +1 -1
- data/lib/alda-rb.rb +1 -0
- metadata +17 -7
data/lib/alda-rb/repl.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
1
|
require 'colorize'
|
2
2
|
require 'irb/ruby-lex'
|
3
3
|
require 'json'
|
4
|
-
require '
|
4
|
+
require 'reline'
|
5
5
|
require 'stringio'
|
6
|
-
|
7
|
-
|
8
|
-
# :call-seq:
|
9
|
-
# repl() -> nil
|
10
|
-
#
|
11
|
-
# Start a REPL session.
|
12
|
-
def Alda.repl
|
13
|
-
Alda::REPL.new.run
|
14
|
-
end
|
6
|
+
require 'bencode'
|
7
|
+
require 'socket'
|
15
8
|
|
16
9
|
##
|
17
10
|
# An instance of this class is an \REPL session.
|
@@ -32,101 +25,303 @@ end
|
|
32
25
|
# your previous input, run <tt>puts history</tt>.
|
33
26
|
#
|
34
27
|
# Unlike \IRB, this \REPL does not print the result of
|
35
|
-
# the executed codes. Use +p+ if you want.
|
28
|
+
# the executed codes. Use +p+ or +puts+ if you want.
|
36
29
|
#
|
37
30
|
# +Interrupt+ and +SystemExit+ exceptions are rescued and
|
38
31
|
# will not cause the process terminating.
|
39
32
|
# +exit+ terminates the \REPL session instead of the process.
|
40
33
|
#
|
41
|
-
# To start an \REPL session in a ruby program, use
|
34
|
+
# To start an \REPL session in a ruby program, use #run.
|
42
35
|
# To start an \REPL session conveniently from command line,
|
43
|
-
# run command <tt>
|
36
|
+
# run command <tt>alda-irb</tt>.
|
37
|
+
# For details about this command line tool, run <tt>alda-irb --help</tt>.
|
44
38
|
#
|
45
|
-
# $
|
46
|
-
# >
|
47
|
-
#
|
48
|
-
# > piano_ c d e f
|
49
|
-
#
|
39
|
+
# $ alda-irb
|
40
|
+
# > p processes.last
|
41
|
+
# {:id=>"dus", :port=>34317, :state=>nil, :expiry=>nil, :type=>:repl_server}
|
42
|
+
# > piano_; c d e f
|
43
|
+
# piano: [c d e f]
|
50
44
|
# > 5.times do
|
51
|
-
#
|
52
|
-
# >
|
45
|
+
# . c
|
46
|
+
# > end
|
53
47
|
# c c c c c
|
54
|
-
# >
|
55
|
-
#
|
48
|
+
# > score_text
|
49
|
+
# piano: [c d e f]
|
56
50
|
# c c c c c
|
57
51
|
# > play
|
52
|
+
# Playing...
|
58
53
|
# > save 'temp.alda'
|
59
54
|
# > puts `cat temp.alda`
|
60
|
-
#
|
55
|
+
# piano: [c d e f]
|
61
56
|
# c c c c c
|
62
57
|
# > system 'rm temp.alda'
|
63
58
|
# > exit
|
59
|
+
#
|
60
|
+
# Notice that there is a significant difference between \Alda 1 \REPL and \Alda 2 \REPL.
|
61
|
+
# In short, \Alda 2 has a much more powerful \REPL than \Alda 1,
|
62
|
+
# so it dropped the <tt>--history</tt> option in the <tt>alda play</tt> command line interface
|
63
|
+
# ({alda-lang/alda#367}[https://github.com/alda-lang/alda/issues/367]).
|
64
|
+
# It has an nREPL server, and this class simply functions by sending messages to the nREPL server.
|
65
|
+
# However, for \Alda 1, this class maintains necessary information
|
66
|
+
# in the memory of the Ruby program,
|
67
|
+
# and the \REPL is implemented by repeatedly running <tt>alda play</tt> in command line.
|
68
|
+
# Therefore, this class functions differently for \Alda 1 and \Alda 2
|
69
|
+
# and you thus should not modify Alda::generation during an \REPL session.
|
70
|
+
#
|
71
|
+
# It is also possible to use this class as a Ruby wrapper of APIs of the \Alda nREPL server
|
72
|
+
# in \Alda 2.
|
73
|
+
# In this usage, you never need to call #run, and you call #message or #raw_message instead.
|
74
|
+
#
|
75
|
+
# repl = Alda::REPL.new
|
76
|
+
# repl.message :eval_and_play, code: 'piano: c d e f' # => nil
|
77
|
+
# repl.message :eval_and_play, code: 'g a b > c' # => nil
|
78
|
+
# repl.message :score_text # => "piano: [c d e f]\ng a b > c\n"
|
79
|
+
# repl.message :eval_and_play, code: 'this will cause an error' # (raises Alda::NREPLServerError)
|
64
80
|
class Alda::REPL
|
65
81
|
|
66
82
|
##
|
67
83
|
# The score object used in Alda::REPL.
|
68
84
|
#
|
69
85
|
# Includes Alda, so it can refer to alda commandline.
|
86
|
+
# However, the methods Alda::Score#play, Alda::Score#parse and Alda::Score#export
|
87
|
+
# are still retained instead of being overridden by the included module.
|
70
88
|
#
|
71
89
|
# When you are in an \REPL session, you are actually
|
72
90
|
# in an instance of this class,
|
73
91
|
# so you can call the instance methods down here
|
74
92
|
# when you play with an \REPL.
|
75
|
-
class TempScore < Alda::Score
|
93
|
+
class TempScore < ::Alda::Score
|
76
94
|
include Alda
|
77
95
|
|
78
|
-
|
79
|
-
define_method meth, Score.instance_method(meth)
|
96
|
+
%i[play parse export].each do |meth|
|
97
|
+
define_method meth, Alda::Score.instance_method(meth)
|
80
98
|
end
|
81
99
|
|
100
|
+
##
|
101
|
+
# :call-seq:
|
102
|
+
# new(session) -> TempScore
|
103
|
+
#
|
104
|
+
# Creates a new TempScore for the given \REPL session specified by +session+.
|
105
|
+
# It is called in Alda::REPL::new.
|
82
106
|
def initialize session
|
83
107
|
super()
|
84
108
|
@session = session
|
85
109
|
end
|
86
110
|
|
111
|
+
##
|
112
|
+
# :call-seq:
|
113
|
+
# to_s -> String
|
114
|
+
#
|
115
|
+
# Overrides Alda::Score#to_s.
|
116
|
+
# Returns the history.
|
117
|
+
#
|
118
|
+
# $ alda-irb
|
119
|
+
# > harmonica_; a b c
|
120
|
+
# harmonica: [a b c]
|
121
|
+
# > guitar_; c g e
|
122
|
+
# guitar: [c g e]
|
123
|
+
# > p to_s
|
124
|
+
# "harmonica: [a b c]\nguitar: [c g e]\n"
|
87
125
|
def to_s
|
88
|
-
history
|
89
|
-
end
|
90
|
-
|
91
|
-
def history
|
92
|
-
@session.history.to_s
|
126
|
+
@session.history
|
93
127
|
end
|
94
128
|
|
129
|
+
##
|
130
|
+
# :call-seq:
|
131
|
+
# clear_history() -> nil
|
132
|
+
#
|
133
|
+
# Clears all the modifications that have been made to the score
|
134
|
+
# and start a new one.
|
135
|
+
# See #score for an example.
|
95
136
|
def clear_history
|
96
137
|
@session.clear_history
|
97
138
|
end
|
139
|
+
alias new clear_history
|
140
|
+
alias new_score clear_history
|
98
141
|
|
142
|
+
##
|
143
|
+
# :call-seq:
|
144
|
+
# get_binding() -> Binding
|
145
|
+
#
|
146
|
+
# Returns a Binding for the instance eval local environment of this score.
|
147
|
+
# Different callings of this method will return different bindings,
|
148
|
+
# and they do not share local variables.
|
149
|
+
# This method is called in Alda::REPL::new.
|
150
|
+
#
|
151
|
+
# $ alda-irb
|
152
|
+
# > p get_binding.receiver == self
|
153
|
+
# true
|
99
154
|
def get_binding
|
100
155
|
binding
|
101
156
|
end
|
102
157
|
|
158
|
+
##
|
159
|
+
# :call-seq:
|
160
|
+
# score() -> nil
|
161
|
+
#
|
162
|
+
# Print the history (all \Alda code of the score).
|
163
|
+
#
|
164
|
+
# $ alda-irb
|
165
|
+
# > violin_; a b
|
166
|
+
# violin: [a b]
|
167
|
+
# > score
|
168
|
+
# violin: [a b]
|
169
|
+
# > clear_history
|
170
|
+
# > score
|
171
|
+
# > viola_; c
|
172
|
+
# viola: c
|
173
|
+
# > score
|
174
|
+
# viola: c
|
103
175
|
def score
|
104
|
-
|
176
|
+
print @session.color ? @session.history.blue : @session.history
|
177
|
+
nil
|
105
178
|
end
|
179
|
+
alias score_text score
|
106
180
|
|
181
|
+
##
|
182
|
+
# :call-seq:
|
183
|
+
# map() -> nil
|
184
|
+
#
|
185
|
+
# Prints a data representation of the score.
|
186
|
+
# This is the output that you get when you call Alda::Score#parse.
|
107
187
|
def map
|
108
|
-
|
109
|
-
|
188
|
+
json = Alda.v1? ? parse : @session.message(:score_data)
|
189
|
+
json = JSON.generate JSON.parse(json), indent: ' ', space: ' ', object_nl: ?\n, array_nl: ?\n
|
190
|
+
puts @session.color ? json.blue : json
|
191
|
+
end
|
192
|
+
alias score_data map
|
193
|
+
|
194
|
+
##
|
195
|
+
# :call-seq:
|
196
|
+
# score_events() -> nil
|
197
|
+
#
|
198
|
+
# Prints the parsed events output of the score.
|
199
|
+
# This is the output that you get when you call Alda::Score#parse with <tt>output: :events</tt>.
|
200
|
+
def score_events
|
201
|
+
json = Alda.v1? ? parse(output: :events) : @session.message(:score_events)
|
202
|
+
json = JSON.generate JSON.parse(json), indent: ' ', space: ' ', object_nl: ?\n, array_nl: ?\n
|
203
|
+
puts @session.color ? json.blue : json
|
110
204
|
end
|
111
205
|
|
112
206
|
alias quit exit
|
113
|
-
alias new clear_history
|
114
207
|
end
|
115
208
|
|
116
209
|
##
|
117
|
-
# The
|
118
|
-
attr_reader :
|
210
|
+
# The host of the nREPL server. Only useful in \Alda 2.
|
211
|
+
attr_reader :host
|
212
|
+
|
213
|
+
##
|
214
|
+
# The port of the nREPL server. Only useful in \Alda 2.
|
215
|
+
attr_reader :port
|
216
|
+
|
217
|
+
##
|
218
|
+
# Whether the output should be colored.
|
219
|
+
attr_accessor :color
|
220
|
+
|
221
|
+
##
|
222
|
+
# Whether a preview of what \Alda code will be played everytime you input ruby codes.
|
223
|
+
attr_accessor :preview
|
119
224
|
|
120
225
|
##
|
121
226
|
# :call-seq:
|
122
|
-
# new() -> Alda::REPL
|
227
|
+
# new(**opts) -> Alda::REPL
|
123
228
|
#
|
124
229
|
# Creates a new Alda::REPL.
|
125
|
-
|
230
|
+
# The parameter +color+ specifies whether the output should be colored (sets #color).
|
231
|
+
# The parameter +preview+ specifies whether a preview of what \Alda code will be played
|
232
|
+
# everytime you input ruby codes (sets #preview).
|
233
|
+
#
|
234
|
+
# The +opts+ are passed to the command line of <tt>alda repl</tt>.
|
235
|
+
# Available options are +host+, +port+, etc.
|
236
|
+
# Run <tt>alda repl --help</tt> for more info.
|
237
|
+
# If +port+ is specified and +host+ is not or is specified to be <tt>"localhost"</tt>
|
238
|
+
# or <tt>"127.0.0.1"</tt>, then this method will try to connect to an existing
|
239
|
+
# \Alda REPL server.
|
240
|
+
# A new one will be started only if no existing server is found.
|
241
|
+
#
|
242
|
+
# The +opts+ are ignored in \Alda 1.
|
243
|
+
def initialize color: true, preview: true, **opts
|
126
244
|
@score = TempScore.new self
|
127
245
|
@binding = @score.get_binding
|
128
246
|
@lex = RubyLex.new
|
129
|
-
@
|
247
|
+
@color = color
|
248
|
+
@preview = preview
|
249
|
+
setup_repl opts
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# :call-seq:
|
254
|
+
# setup_repl(opts) -> nil
|
255
|
+
#
|
256
|
+
# Sets up the \REPL session.
|
257
|
+
# This method is called in ::new.
|
258
|
+
# After you #terminate the session,
|
259
|
+
# you cannot use the \REPL anymore unless you call this method again.
|
260
|
+
def setup_repl opts
|
261
|
+
if Alda.v1?
|
262
|
+
@history = StringIO.new
|
263
|
+
else
|
264
|
+
if opts[:port] && [nil, 'localhost', '127.0.0.1'].include?(opts[:host]) &&
|
265
|
+
Alda.processes.any? { _1[:port] == opts[:port].to_i && _1[:type] == :repl_server }
|
266
|
+
@port = opts[:port].to_i
|
267
|
+
@host = opts[:host] || 'localhost'
|
268
|
+
else
|
269
|
+
@nrepl_pipe = Alda.pipe :repl, **opts, server: true
|
270
|
+
/nrepl:\/\/(?<host>[a-zA-Z0-9._\-]+):(?<port>\d+)/ =~ @nrepl_pipe.gets
|
271
|
+
@host = host
|
272
|
+
@port = port.to_i
|
273
|
+
Process.detach @nrepl_pipe.pid
|
274
|
+
end
|
275
|
+
@socket = TCPSocket.new @host, @port
|
276
|
+
@bencode_parser = BEncode::Parser.new @socket
|
277
|
+
end
|
278
|
+
nil
|
279
|
+
end
|
280
|
+
|
281
|
+
##
|
282
|
+
# :call-seq:
|
283
|
+
# raw_message(contents) -> Hash
|
284
|
+
#
|
285
|
+
# Sends a message to the nREPL server and returns the response.
|
286
|
+
# The parameter +contents+ is a Hash or a JSON string.
|
287
|
+
#
|
288
|
+
# repl = Alda::REPL.new
|
289
|
+
# repl.raw_message op: 'describe' # => {"ops"=>...}
|
290
|
+
def raw_message contents
|
291
|
+
Alda::GenerationError.assert_generation [:v2]
|
292
|
+
contents = JSON.parse contents if contents.is_a? String
|
293
|
+
@socket.write contents.bencode
|
294
|
+
@bencode_parser.parse!
|
295
|
+
end
|
296
|
+
|
297
|
+
##
|
298
|
+
# :call-seq:
|
299
|
+
# message(op, **params) -> String or Hash
|
300
|
+
#
|
301
|
+
# Sends a message to the nREPL server with the following format,
|
302
|
+
# with +op+ being the operation name (the +op+ field in the message),
|
303
|
+
# and +params+ being the parameters (other fields in the message).
|
304
|
+
# Then, this method analyzes the response.
|
305
|
+
# If there is an error, raises Alda::NREPLServerError.
|
306
|
+
# Otherwise, if the response contains only one field, return the content of that field (a String).
|
307
|
+
# Otherwise, return the whole response as a Hash.
|
308
|
+
#
|
309
|
+
# repl = Alda::REPL.new
|
310
|
+
# repl.message :eval_and_play, code: 'piano: c d e f' # => nil
|
311
|
+
# repl.message :eval_and_play, code: 'g a b > c' # => nil
|
312
|
+
# repl.message :score_text # => "piano: [c d e f]\ng a b > c\n"
|
313
|
+
# repl.message :eval_and_play, code: 'this will cause an error' # (raises Alda::NREPLServerError)
|
314
|
+
def message op, **params
|
315
|
+
result = raw_message op: Alda::Utils.snake_to_slug(op), **params
|
316
|
+
result.transform_keys! { Alda::Utils.slug_to_snake _1 }
|
317
|
+
if result.delete(:status).include? 'error'
|
318
|
+
raise Alda::NREPLServerError.new @host, @port, result.delete(:problems)
|
319
|
+
end
|
320
|
+
case result.size
|
321
|
+
when 0 then nil
|
322
|
+
when 1 then result.values.first
|
323
|
+
else result
|
324
|
+
end
|
130
325
|
end
|
131
326
|
|
132
327
|
##
|
@@ -134,10 +329,11 @@ class Alda::REPL
|
|
134
329
|
# run() -> nil
|
135
330
|
#
|
136
331
|
# Runs the session.
|
137
|
-
# Includes the start, the main loop, and the termination.
|
332
|
+
# Includes the start (#start), the main loop, and the termination (#terminate).
|
138
333
|
def run
|
139
334
|
start
|
140
335
|
while code = rb_code
|
336
|
+
next if code.empty?
|
141
337
|
break unless process_rb_code code
|
142
338
|
end
|
143
339
|
terminate
|
@@ -159,18 +355,37 @@ class Alda::REPL
|
|
159
355
|
# It can intelligently continue reading if the code is not complete yet.
|
160
356
|
def rb_code
|
161
357
|
result = ''
|
358
|
+
indent = 0
|
162
359
|
begin
|
163
|
-
|
164
|
-
return unless buf
|
165
|
-
result.concat buf, ?\n
|
360
|
+
result.concat readline(indent).tap { return unless _1 }, ?\n
|
166
361
|
ltype, indent, continue, block_open = @lex.check_state result
|
167
362
|
rescue Interrupt
|
168
363
|
$stdout.puts
|
169
|
-
|
364
|
+
return ''
|
170
365
|
end while ltype || indent.nonzero? || continue || block_open
|
171
366
|
result
|
172
367
|
end
|
173
368
|
|
369
|
+
##
|
370
|
+
# :call-seq:
|
371
|
+
# readline(indent = 0) -> String
|
372
|
+
#
|
373
|
+
# Prompts the user to input a line.
|
374
|
+
# The parameter +indent+ is the indentation level.
|
375
|
+
# Twice the number of spaces is already in the input field before the user fills in.
|
376
|
+
# The prompt hint is different for zero +indent+ and nonzero +indent+.
|
377
|
+
# Returns the user input.
|
378
|
+
def readline indent = 0
|
379
|
+
prompt = indent.nonzero? ? '. ' : '> '
|
380
|
+
prompt = prompt.green if @color
|
381
|
+
Reline.pre_input_hook = -> do
|
382
|
+
Reline.insert_text ' ' * indent
|
383
|
+
Reline.redisplay
|
384
|
+
Reline.pre_input_hook = nil
|
385
|
+
end
|
386
|
+
Reline.readline prompt, true
|
387
|
+
end
|
388
|
+
|
174
389
|
##
|
175
390
|
# :call-seq:
|
176
391
|
# process_rb_code(code) -> true or false
|
@@ -182,18 +397,16 @@ class Alda::REPL
|
|
182
397
|
@score.clear
|
183
398
|
begin
|
184
399
|
@binding.eval code
|
185
|
-
rescue StandardError, ScriptError => e
|
400
|
+
rescue StandardError, ScriptError, Interrupt => e
|
186
401
|
$stderr.print e.full_message
|
187
402
|
return true
|
188
|
-
rescue Interrupt
|
189
|
-
return true
|
190
403
|
rescue SystemExit
|
191
404
|
return false
|
192
405
|
end
|
193
406
|
code = @score.events_alda_codes
|
194
407
|
unless code.empty?
|
195
|
-
$stdout.puts code.yellow
|
196
|
-
play_score code
|
408
|
+
$stdout.puts @color ? code.yellow : code
|
409
|
+
try_command { play_score code }
|
197
410
|
end
|
198
411
|
true
|
199
412
|
end
|
@@ -202,12 +415,15 @@ class Alda::REPL
|
|
202
415
|
# :call-seq:
|
203
416
|
# try_command() { ... } -> obj
|
204
417
|
#
|
205
|
-
#
|
418
|
+
# Run the block.
|
419
|
+
# In \Alda 1, catches Alda::CommandLineError.
|
420
|
+
# In \Alda 2, catches Alda::NREPLServerError.
|
421
|
+
# If an error is caught, prints the error message (in red if #color is true).
|
206
422
|
def try_command
|
207
423
|
begin
|
208
424
|
yield
|
209
|
-
rescue Alda::CommandLineError => e
|
210
|
-
puts e.message.red
|
425
|
+
rescue Alda.v1? ? Alda::CommandLineError : Alda::NREPLServerError => e
|
426
|
+
puts @color ? e.message.red : e.message
|
211
427
|
end
|
212
428
|
end
|
213
429
|
|
@@ -215,11 +431,15 @@ class Alda::REPL
|
|
215
431
|
# :call-seq:
|
216
432
|
# play_score(code) -> nil
|
217
433
|
#
|
218
|
-
#
|
434
|
+
# Appends +code+ to the history and plays the +code+ as \Alda code.
|
435
|
+
# In \Alda 1, plays the score by sending +code+ to command line alda.
|
436
|
+
# In \Alda 2, sends +code+ to the nREPL server for evaluating and playing.
|
219
437
|
def play_score code
|
220
|
-
|
438
|
+
if Alda.v1?
|
221
439
|
Alda.play code: code, history: @history
|
222
440
|
@history.puts code
|
441
|
+
else
|
442
|
+
message :eval_and_play, code: code
|
223
443
|
end
|
224
444
|
end
|
225
445
|
|
@@ -228,18 +448,50 @@ class Alda::REPL
|
|
228
448
|
# terminate() -> nil
|
229
449
|
#
|
230
450
|
# Terminates the REPL session.
|
231
|
-
#
|
451
|
+
# In \Alda 1, just calls #clear_history.
|
452
|
+
# In \Alda 2, sends a SIGINT to the nREPL server if it was spawned by the Ruby program.
|
232
453
|
def terminate
|
233
|
-
|
454
|
+
if Alda.v1?
|
455
|
+
clear_history
|
456
|
+
else
|
457
|
+
if @nrepl_pipe
|
458
|
+
if Alda::Utils.win_platform?
|
459
|
+
system 'taskkill', '/f', '/pid', @nrepl_pipe.pid.to_s
|
460
|
+
else
|
461
|
+
Process.kill :INT, @nrepl_pipe.pid
|
462
|
+
end
|
463
|
+
@nrepl_pipe.close
|
464
|
+
end
|
465
|
+
@socket.close
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
##
|
470
|
+
# :call-seq:
|
471
|
+
# history() -> String
|
472
|
+
#
|
473
|
+
# In \Alda 1, it is the same as an attribute reader.
|
474
|
+
# In \Alda 2, it asks the nREPL server for its score text and returns it.
|
475
|
+
def history
|
476
|
+
if Alda.v1?
|
477
|
+
@history
|
478
|
+
else
|
479
|
+
try_command { message :score_text }
|
480
|
+
end
|
234
481
|
end
|
235
482
|
|
236
483
|
##
|
237
484
|
# :call-seq:
|
238
485
|
# clear_history() -> nil
|
239
486
|
#
|
240
|
-
#
|
487
|
+
# In \Alda 1, clears #history.
|
488
|
+
# In \Alda 2, askes the nREPL server to clear its history (start a new score).
|
241
489
|
def clear_history
|
242
|
-
|
490
|
+
if Alda.v1?
|
491
|
+
@history = StringIO.new
|
492
|
+
else
|
493
|
+
try_command { message :new_score }
|
494
|
+
end
|
243
495
|
nil
|
244
496
|
end
|
245
497
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
##
|
2
|
+
# Some useful functions.
|
3
|
+
module Alda::Utils
|
4
|
+
|
5
|
+
##
|
6
|
+
# :call-seq:
|
7
|
+
# warn(message) -> nil
|
8
|
+
#
|
9
|
+
# Prints a warning message to standard error, appended by a newline.
|
10
|
+
# The message is prefixed with the filename and lineno of the caller
|
11
|
+
# (the lowest level where the file is not an alda-rb source file).
|
12
|
+
def warn message
|
13
|
+
location = caller_locations.find { !_1.path.start_with? __dir__ }
|
14
|
+
Warning.warn "#{location.path}:#{location.lineno}: #{message}\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# :call-seq:
|
19
|
+
# win_platform? -> true or false
|
20
|
+
#
|
21
|
+
# Returns whether the current platform is Windows.
|
22
|
+
def win_platform?
|
23
|
+
Gem.win_platform?
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# :call-seq:
|
28
|
+
# snake_to_slug(sym) -> String
|
29
|
+
#
|
30
|
+
# Converts a snake_case Symbol to a slug-case String.
|
31
|
+
# The inverse of ::slug_to_snake.
|
32
|
+
def snake_to_slug sym
|
33
|
+
sym.to_s.gsub ?_, ?-
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# :call-seq:
|
38
|
+
# slug_to_snake(str) -> Symbol
|
39
|
+
#
|
40
|
+
# Converts a slug-case String to a snake_case Symbol.
|
41
|
+
# The inverse of ::snake_to_slug.
|
42
|
+
def slug_to_snake str
|
43
|
+
str.to_s.gsub(?-, ?_).to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
module_function :warn, :win_platform?, :snake_to_slug, :slug_to_snake
|
47
|
+
end
|
data/lib/alda-rb/version.rb
CHANGED
data/lib/alda-rb.rb
CHANGED
metadata
CHANGED
@@ -1,26 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alda-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ulysses Zhan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
15
15
|
- UlyssesZhan@gmail.com
|
16
|
-
executables:
|
16
|
+
executables:
|
17
|
+
- alda-irb
|
17
18
|
extensions: []
|
18
19
|
extra_rdoc_files: []
|
19
20
|
files:
|
21
|
+
- ".github/workflows/main.yml"
|
20
22
|
- ".gitignore"
|
21
23
|
- ".travis.yml"
|
24
|
+
- CHANGELOG.md
|
22
25
|
- CODE_OF_CONDUCT.md
|
23
26
|
- Gemfile
|
27
|
+
- Gemfile.lock
|
24
28
|
- LICENSE.txt
|
25
29
|
- README.md
|
26
30
|
- Rakefile
|
@@ -31,10 +35,12 @@ files:
|
|
31
35
|
- examples/bwv846_prelude.rb
|
32
36
|
- examples/clapping_music.rb
|
33
37
|
- examples/dot_accessor.rb
|
38
|
+
- examples/dynamics.rb
|
34
39
|
- examples/entropy.rb
|
35
40
|
- examples/hanon.rb
|
36
41
|
- examples/hello_world.rb
|
37
42
|
- examples/key_signature.rb
|
43
|
+
- examples/marriage_d_amour.rb
|
38
44
|
- examples/midi_note_numbers.rb
|
39
45
|
- examples/modes2.rb
|
40
46
|
- examples/multi_poly.rb
|
@@ -42,7 +48,10 @@ files:
|
|
42
48
|
- examples/phase.rb
|
43
49
|
- examples/seconds_and_milliseconds.rb
|
44
50
|
- examples/showcase.rb
|
51
|
+
- examples/track-volume.rb
|
52
|
+
- examples/variables-2.rb
|
45
53
|
- examples/variables.rb
|
54
|
+
- exe/alda-irb
|
46
55
|
- lib/alda-rb.rb
|
47
56
|
- lib/alda-rb/commandline.rb
|
48
57
|
- lib/alda-rb/error.rb
|
@@ -50,14 +59,15 @@ files:
|
|
50
59
|
- lib/alda-rb/event_list.rb
|
51
60
|
- lib/alda-rb/patches.rb
|
52
61
|
- lib/alda-rb/repl.rb
|
62
|
+
- lib/alda-rb/utils.rb
|
53
63
|
- lib/alda-rb/version.rb
|
54
|
-
homepage: https://github.
|
64
|
+
homepage: https://ulysseszh.github.io/doc/alda-rb
|
55
65
|
licenses:
|
56
66
|
- MIT
|
57
67
|
metadata:
|
58
|
-
homepage_uri: https://github.
|
68
|
+
homepage_uri: https://ulysseszh.github.io/doc/alda-rb
|
59
69
|
source_code_uri: https://github.com/UlyssesZh/alda-rb
|
60
|
-
changelog_uri: https://github.
|
70
|
+
changelog_uri: https://ulysseszh.github.io/doc/alda-rb/CHANGELOG_md.html
|
61
71
|
post_install_message:
|
62
72
|
rdoc_options: []
|
63
73
|
require_paths:
|
@@ -73,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
83
|
- !ruby/object:Gem::Version
|
74
84
|
version: '0'
|
75
85
|
requirements: []
|
76
|
-
rubygems_version: 3.1.
|
86
|
+
rubygems_version: 3.1.6
|
77
87
|
signing_key:
|
78
88
|
specification_version: 4
|
79
89
|
summary: A Ruby library for live-coding music with Alda.
|