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.
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 'readline'
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 Alda::repl.
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>ruby -ralda-rb -e "Alda.repl"</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
- # $ ruby -ralda-rb -e "Alda.repl"
46
- # > puts status
47
- # [27713] Server up (2/2 workers available, backend port: 33245)
48
- # > piano_ c d e f
49
- # [piano: c d e f]
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
- # > c
52
- # > end
45
+ # . c
46
+ # > end
53
47
  # c c c c c
54
- # > puts history
55
- # [piano: c d e f]
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
- # [piano: c d e f]
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
- Score.instance_methods(false).each do |meth|
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
- puts history
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
- puts JSON.generate JSON.parse(parse),
109
- indent: ' ', space: ' ', object_nl: ?\n, array_nl: ?\n
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 history.
118
- attr_reader :history
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
- def initialize
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
- @history = StringIO.new
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
- buf = Readline.readline '> '.green, true
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
- retry
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
- # Tries to run the block and rescue Alda::CommandLineError.
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
- # Plays the score by sending +code+ to command line alda.
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
- try_command do
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
- # Currently just clears #history.
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
- clear_history
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
- # Clears #history.
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
- @history = StringIO.new
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
@@ -7,5 +7,5 @@ module Alda
7
7
  # The version number of alda-rb.
8
8
  #
9
9
  # The same as that in alda-rb gem spec.
10
- VERSION = '0.2.1'
10
+ VERSION = '0.3.0'
11
11
  end
data/lib/alda-rb.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'alda-rb/version'
4
4
  require 'alda-rb/patches'
5
+ require 'alda-rb/utils'
5
6
  require 'alda-rb/error'
6
7
  require 'alda-rb/commandline'
7
8
  require 'alda-rb/event_list'
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.2.1
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: 2020-08-13 00:00:00.000000000 Z
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.com/UlyssesZh/alda-rb
64
+ homepage: https://ulysseszh.github.io/doc/alda-rb
55
65
  licenses:
56
66
  - MIT
57
67
  metadata:
58
- homepage_uri: https://github.com/UlyssesZh/alda-rb
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.com/UlyssesZh/alda-rb/releases
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.2
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.