musa-dsl 0.14.26 → 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Gemfile +0 -1
  4. data/README.md +5 -1
  5. data/lib/musa-dsl.rb +54 -11
  6. data/lib/musa-dsl/core-ext.rb +7 -13
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  8. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  9. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  10. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  11. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  12. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  13. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  14. data/lib/musa-dsl/core-ext/with.rb +26 -0
  15. data/lib/musa-dsl/datasets.rb +8 -3
  16. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  17. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  18. data/lib/musa-dsl/datasets/e.rb +61 -0
  19. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  20. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  21. data/lib/musa-dsl/datasets/helper.rb +41 -0
  22. data/lib/musa-dsl/datasets/p.rb +68 -0
  23. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  24. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  25. data/lib/musa-dsl/datasets/ps.rb +113 -0
  26. data/lib/musa-dsl/datasets/score.rb +210 -0
  27. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  28. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  32. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  33. data/lib/musa-dsl/datasets/v.rb +23 -0
  34. data/lib/musa-dsl/generative.rb +5 -5
  35. data/lib/musa-dsl/generative/backboner.rb +274 -0
  36. data/lib/musa-dsl/generative/darwin.rb +102 -96
  37. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  38. data/lib/musa-dsl/generative/markov.rb +56 -53
  39. data/lib/musa-dsl/generative/variatio.rb +234 -222
  40. data/lib/musa-dsl/logger.rb +1 -0
  41. data/lib/musa-dsl/logger/logger.rb +31 -0
  42. data/lib/musa-dsl/matrix.rb +1 -0
  43. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  44. data/lib/musa-dsl/midi.rb +2 -2
  45. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  46. data/lib/musa-dsl/midi/midi-voices.rb +183 -182
  47. data/lib/musa-dsl/music.rb +5 -5
  48. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  49. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  50. data/lib/musa-dsl/music/chords.rb +236 -238
  51. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  52. data/lib/musa-dsl/music/scales.rb +331 -332
  53. data/lib/musa-dsl/musicxml.rb +1 -0
  54. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  55. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  56. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  57. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  58. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  59. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  60. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  61. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  62. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  63. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  64. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  65. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  66. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  67. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  68. data/lib/musa-dsl/neumalang.rb +1 -1
  69. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  70. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  71. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  72. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  73. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  74. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  75. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  76. data/lib/musa-dsl/neumas.rb +5 -0
  77. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  78. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  79. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  80. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  81. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  82. data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
  83. data/lib/musa-dsl/repl.rb +1 -1
  84. data/lib/musa-dsl/repl/repl.rb +105 -105
  85. data/lib/musa-dsl/sequencer.rb +1 -1
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +562 -270
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +199 -199
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
  91. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  92. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  93. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  94. data/lib/musa-dsl/series.rb +1 -1
  95. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  96. data/lib/musa-dsl/series/base-series.rb +171 -168
  97. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  98. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  99. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  100. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  101. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  102. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  103. data/lib/musa-dsl/series/series.rb +2 -0
  104. data/lib/musa-dsl/transcription.rb +4 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  106. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  107. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  108. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  109. data/lib/musa-dsl/transport.rb +6 -6
  110. data/lib/musa-dsl/transport/clock.rb +26 -26
  111. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  112. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  113. data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
  114. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  115. data/lib/musa-dsl/transport/timer.rb +28 -26
  116. data/lib/musa-dsl/transport/transport.rb +99 -95
  117. data/musa-dsl.gemspec +3 -3
  118. metadata +73 -24
  119. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  120. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  121. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  122. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  123. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  124. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  125. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  126. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  127. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  128. data/lib/musa-dsl/generative/rules.rb +0 -282
  129. data/lib/musa-dsl/neuma.rb +0 -1
  130. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -0,0 +1,21 @@
1
+ grammar Musa::Neumalang::Neumalang::Parser::Grammar::Process
2
+ include Musa::Neumalang::Neumalang::Parser::Grammar::Vectors
3
+
4
+ rule process
5
+ process_of_vectors | process_of_packed_vectors
6
+ end
7
+
8
+ rule process_of_vectors
9
+ (first:raw_vector
10
+ (optional_separation
11
+ bar optional_separation durations:raw_number optional_separation bar optional_separation
12
+ rest:raw_vector)+) <Musa::Neumalang::Neumalang::Parser::ProcessOfVectors>
13
+ end
14
+
15
+ rule process_of_packed_vectors
16
+ (first:raw_packed_vector
17
+ (optional_separation
18
+ bar optional_separation durations:raw_number optional_separation bar optional_separation
19
+ rest:raw_packed_vector)+) <Musa::Neumalang::Neumalang::Parser::ProcessOfVectors>
20
+ end
21
+ end
@@ -0,0 +1,67 @@
1
+ grammar Musa::Neumalang::Neumalang::Parser::Grammar::Terminals
2
+ rule everything_except_comment
3
+ ~/((\*\/)|(\/\*))/m
4
+ end
5
+
6
+ rule everything_except_braces
7
+ ~/({|})/m
8
+ end
9
+
10
+ rule everything_except_double_quote
11
+ ~/(\")/m
12
+ end
13
+
14
+ rule comment
15
+ (lcomment complex_comment rcomment)
16
+ end
17
+
18
+ rule complex_comment
19
+ everything_except_comment? (lcomment complex_comment rcomment)* everything_except_comment?
20
+ end
21
+
22
+ rule attribute_change
23
+ space | dot | rbracket | rpar | rbrace | eol | eos
24
+ end
25
+
26
+ rule true 'true' end
27
+ rule false 'false' end
28
+ rule nil 'nil' end
29
+
30
+ rule optional_separation (spaces | comment)* end
31
+ rule separation (spaces | comment)+ end
32
+
33
+ rule double_quote '"' end
34
+ rule single_quote '\'' end
35
+ rule dot '.' end
36
+ rule mid_dot '·' end
37
+ rule comma ',' end
38
+ rule colon ':' end
39
+ rule double_colon '::' end
40
+ rule bar '|' end
41
+ rule double_bar '||' end
42
+ rule asterisk '*' end
43
+ rule slash '/' end
44
+ rule lpar '(' end
45
+ rule rpar ')' end
46
+ rule lbrace '{' end
47
+ rule rbrace '}' end
48
+ rule lbracket '[' end
49
+ rule rbracket ']' end
50
+ rule lacute '<' end
51
+ rule racute '>' end
52
+ rule at '@' end
53
+ rule ampersand '&' end
54
+ rule equal '=' end
55
+ rule lcomment '/*' end
56
+ rule rcomment '*/' end
57
+ rule hsh '#' end
58
+ rule underscore '_' end
59
+ rule minus '-' end
60
+ rule plus '+' end
61
+
62
+ rule eol /$/ end
63
+ rule eos /\Z/ end
64
+
65
+ rule space /[[:space:]]/ end
66
+ rule spaces /[[:space:]]/+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ grammar Musa::Neumalang::Neumalang::Parser::Grammar::Vectors
2
+ include Musa::Neumalang::Neumalang::Parser::Grammar::Datatypes
3
+
4
+ rule vector
5
+ (optional_separation raw_vector) <Musa::Neumalang::Neumalang::Parser::Vector>
6
+ end
7
+
8
+ rule raw_vector
9
+ (lpar (optional_separation raw_number)+ optional_separation rpar) <Musa::Neumalang::Neumalang::Parser::RawVector>
10
+ end
11
+
12
+ rule packed_vector
13
+ (optional_separation raw_packed_vector) <Musa::Neumalang::Neumalang::Parser::PackedVector>
14
+ end
15
+
16
+ rule raw_packed_vector
17
+ (lpar (optional_separation key_value)+ optional_separation rpar) <Musa::Neumalang::Neumalang::Parser::RawPackedVector>
18
+ end
19
+
20
+ rule key_value
21
+ (raw_symbol colon optional_separation raw_number) { [ capture(:raw_symbol).value, capture(:raw_number).value ] }
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ require_relative 'neumas/neuma-gdv-decoder'
2
+ require_relative 'neumas/neuma-gdvd-decoder'
3
+
4
+ require_relative 'neumas/array-to-neumas'
5
+ require_relative 'neumas/string-to-neumas'
@@ -0,0 +1,34 @@
1
+ require_relative '../series'
2
+ require_relative '../neumalang'
3
+
4
+ module Musa
5
+ module Extension
6
+ module Neumas
7
+ refine Array do
8
+ def to_neumas
9
+ if length > 1
10
+ MERGE(*collect { |e| convert_to_neumas(e) })
11
+ else
12
+ convert_to_neumas(first)
13
+ end
14
+ end
15
+
16
+ alias_method :neumas, :to_neumas
17
+ alias_method :n, :to_neumas
18
+
19
+ private
20
+
21
+ def convert_to_neumas(e)
22
+ case e
23
+ when Musa::Neumas::Neuma::Serie then e
24
+ when Musa::Neumas::Neuma::Parallel then _SE([e], extends: Musa::Neumas::Neuma::Serie)
25
+ when String then e.to_neumas
26
+ else
27
+ raise ArgumentError, "Don't know how to convert to neumas #{e}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,63 @@
1
+ require_relative 'neumas'
2
+
3
+ module Musa::Neumas
4
+ module Decoders
5
+ class ProtoDecoder
6
+ def subcontext
7
+ self
8
+ end
9
+
10
+ def decode(_element)
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+
15
+ class DifferentialDecoder < ProtoDecoder
16
+ def decode(gdvd)
17
+ process gdvd
18
+ end
19
+
20
+ def process(_gdvd)
21
+ raise NotImplementedError
22
+ end
23
+ end
24
+
25
+ class Decoder < DifferentialDecoder
26
+ def initialize(base, transcriptor: nil)
27
+ @base = base
28
+ @last = base.clone
29
+
30
+ @transcriptor = transcriptor
31
+ end
32
+
33
+ attr_accessor :transcriptor
34
+ attr_reader :base
35
+
36
+ def base=(base)
37
+ @base = base
38
+ @last = base.clone
39
+ end
40
+
41
+ def subcontext
42
+ Decoder.new @base
43
+ end
44
+
45
+ def decode(attributes)
46
+ result = apply process(attributes), on: @last
47
+
48
+ @last = result.clone
49
+
50
+ if @transcriptor
51
+ @transcriptor.transcript(result)
52
+ else
53
+ result
54
+ end
55
+ end
56
+
57
+ def apply(_action, on:)
58
+ raise NotImplementedError
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,57 @@
1
+ require_relative 'neuma-decoder'
2
+
3
+ module Musa::Neumas
4
+ module Decoders
5
+ class NeumaDecoder < Decoder # to get a GDV
6
+ def initialize(scale, base_duration: nil, transcriptor: nil, base: nil)
7
+ @base_duration = base_duration
8
+ @base_duration ||= base[:duration] if base
9
+ @base_duration ||= Rational(1,4)
10
+
11
+ base ||= { grade: 0, octave: 0, duration: @base_duration, velocity: 1 }
12
+
13
+ @scale = scale
14
+
15
+ super base, transcriptor: transcriptor
16
+ end
17
+
18
+ attr_accessor :scale, :base_duration
19
+
20
+ def process(gdvd)
21
+ gdvd = gdvd.clone
22
+
23
+ gdvd.base_duration = @base_duration
24
+
25
+ appogiatura_gdvd = gdvd[:modifiers]&.delete :appogiatura
26
+
27
+ if appogiatura_gdvd
28
+ appogiatura_gdvd = appogiatura_gdvd.clone
29
+ appogiatura_gdvd.base_duration = @base_duration
30
+
31
+ gdvd[:modifiers][:appogiatura] = appogiatura_gdvd
32
+ end
33
+
34
+ gdvd
35
+ end
36
+
37
+ def subcontext
38
+ NeumaDecoder.new @scale, base_duration: @base_duration, transcriptor: @transcriptor, base: @last
39
+ end
40
+
41
+ def apply(gdvd, on:)
42
+ gdv = gdvd.to_gdv @scale, previous: on
43
+
44
+ appogiatura_action = gdvd.dig(:modifiers, :appogiatura)
45
+ gdv[:appogiatura] = appogiatura_action.to_gdv @scale, previous: on if appogiatura_action
46
+
47
+ gdv
48
+ end
49
+
50
+ def inspect
51
+ "GDV NeumaDecoder: @last = #{@last}"
52
+ end
53
+
54
+ alias to_s inspect
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'neuma-decoder'
2
+
3
+ module Musa::Neumas
4
+ module Decoders
5
+ class NeumaDifferentialDecoder < DifferentialDecoder # to get a GDVd
6
+ def initialize(base_duration: nil)
7
+ @base_duration = base_duration || Rational(1,4)
8
+ end
9
+
10
+ def process(gdvd)
11
+ gdvd.clone.tap { |_| _.base_duration = @base_duration }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'string-to-neumas'
2
+
3
+ using Musa::Extension::Neumas
4
+
5
+ module Musa
6
+ module Neumas
7
+ module Neuma
8
+ module Parallel
9
+ include Neuma
10
+ end
11
+
12
+ module Serie
13
+ include Neuma
14
+ end
15
+
16
+ def |(other)
17
+ if is_a?(Parallel)
18
+ clone.tap { |_| _[:parallel] << convert_to_parallel_element(other) }.extend(Parallel)
19
+ else
20
+ { kind: :parallel,
21
+ parallel: [clone, convert_to_parallel_element(other)]
22
+ }.extend(Parallel)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def convert_to_parallel_element(e)
29
+ case e
30
+ when String then { kind: :serie, serie: e.to_neumas }.extend(Neuma)
31
+ else
32
+ raise ArgumentError, "Don't know how to convert to neumas #{e}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../neumalang'
2
+ require_relative '../generative/generative-grammar'
3
+
4
+ module Musa
5
+ module Extension
6
+ module Neumas
7
+ refine String do
8
+ def to_neumas(decode_with: nil, debug: nil)
9
+ Musa::Neumalang::Neumalang.parse(self, decode_with: decode_with, debug: debug)
10
+ end
11
+
12
+ def to_neumas_to_node(decode_with: nil, debug: nil)
13
+ to_neumas(decode_with: decode_with, debug: debug).to_node
14
+ end
15
+
16
+ def |(other)
17
+ case other
18
+ when String
19
+ { kind: :parallel,
20
+ parallel: [{ kind: :serie, serie: self.to_neumas },
21
+ { kind: :serie, serie: other.to_neumas }] }.extend(Musa::Neumas::Neuma::Parallel)
22
+ else
23
+ raise ArgumentError, "Don't know how to parallelize #{other}"
24
+ end
25
+ end
26
+
27
+
28
+ alias_method :neumas, :to_neumas
29
+ alias_method :n, :to_neumas
30
+ alias_method :nn, :to_neumas_to_node
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1 +1 @@
1
- require 'musa-dsl/repl/repl'
1
+ require_relative 'repl/repl'
@@ -1,142 +1,142 @@
1
1
  require 'socket'
2
2
 
3
3
  module Musa
4
- class REPL
5
- @@repl_mutex = Mutex.new
4
+ module REPL
5
+ class REPL
6
+ @@repl_mutex = Mutex.new
6
7
 
7
- def initialize(binder, port: nil, redirect_stderr: nil, after_eval: nil)
8
- port ||= 1327
9
- redirect_stderr ||= false
8
+ def initialize(binder, port: nil, after_eval: nil)
9
+ port ||= 1327
10
+ redirect_stderr ||= false
10
11
 
11
- @block_source = nil
12
+ @block_source = nil
12
13
 
13
- if binder.receiver.respond_to?(:sequencer) &&
14
- binder.receiver.sequencer.respond_to?(:on_block_error)
14
+ if binder.receiver.respond_to?(:sequencer) &&
15
+ binder.receiver.sequencer.respond_to?(:on_error)
15
16
 
16
- binder.receiver.sequencer.on_block_error do |e|
17
- send_exception e
17
+ binder.receiver.sequencer.on_error do |e|
18
+ send_exception e
19
+ end
18
20
  end
19
- end
20
21
 
21
- @client_threads = []
22
-
23
- @main_thread = Thread.new do
24
- @server = TCPServer.new(port)
25
- begin
26
- while connection = @server.accept
27
- @client_threads << Thread.new do
28
- buffer = nil
29
-
30
- begin
31
- while line = connection.gets
32
- line.chomp!
33
- case line
34
- when '#begin'
35
- buffer = StringIO.new
36
- when '#end'
37
- @@repl_mutex.synchronize do
38
- original_stdout = $stdout
39
- original_stderr = $stderr
40
-
41
- $stdout = connection
42
- $stderr = connection if redirect_stderr
43
-
44
- @block_source = buffer.string
45
-
46
- begin
47
- send_echo @block_source
48
-
49
- binder.eval @block_source, "(repl)", 1
50
- rescue StandardError, ScriptError => e
51
- send_exception e
52
- else
53
- after_eval.call @block_source if after_eval
22
+ @client_threads = []
23
+ @run = true
24
+
25
+ @main_thread = Thread.new do
26
+ @server = TCPServer.new(port)
27
+ begin
28
+ while (connection = @server.accept) && @run
29
+ @client_threads << Thread.new do
30
+ buffer = nil
31
+
32
+ begin
33
+ while (line = connection.gets) && @run
34
+ line.chomp!
35
+ case line
36
+ when '#begin'
37
+ buffer = StringIO.new
38
+ when '#end'
39
+ @@repl_mutex.synchronize do
40
+ @block_source = buffer.string
41
+
42
+ begin
43
+ send_echo @block_source, output: connection
44
+ binder.eval @block_source, "(repl)", 1
45
+
46
+ rescue StandardError, ScriptError => e
47
+ send_exception e, output: connection
48
+ else
49
+ after_eval.call @block_source if after_eval
50
+ end
54
51
  end
55
-
56
- $stdout = original_stdout
57
- $stderr = original_stderr if redirect_stderr
52
+ else
53
+ buffer.puts line
58
54
  end
59
- else
60
- buffer.puts line
61
55
  end
56
+ rescue IOError, Errno::ECONNRESET, Errno::EPIPE => e
57
+ warn e.message
62
58
  end
63
- rescue IOError, Errno::ECONNRESET, Errno::EPIPE => e
64
- warn e.message
65
- end
66
59
 
67
- connection.close
60
+ connection.close
61
+ end
68
62
  end
63
+ rescue Errno::ECONNRESET, Errno::EPIPE => e
64
+ warn e.message
65
+ retry
69
66
  end
70
- rescue Errno::ECONNRESET, Errno::EPIPE => e
71
- warn e.message
72
- retry
73
67
  end
74
68
  end
75
- end
76
69
 
77
- def stop
78
- # TODO
79
- end
70
+ def stop
71
+ @run = false
80
72
 
81
- private
73
+ @main_thread.terminate
74
+ @client_threads.each { |t| t.terminate }
82
75
 
83
- def send_echo(e)
84
- send command: '//echo'
85
- send content: e
86
- send command: '//end'
87
- end
76
+ @main_thread = nil
77
+ @client_threads.clear
78
+ end
88
79
 
89
- def send_exception(e)
80
+ private
90
81
 
91
- send command: '//error'
82
+ def send_echo(e, output:)
83
+ send output: output, command: '//echo'
84
+ send output: output, content: e
85
+ send output: output, command: '//end'
86
+ end
87
+
88
+ def send_exception(e, output:)
92
89
 
93
- selected_backtrace_locations = e.backtrace_locations.select { |bt| bt.path == '(repl)' }
90
+ send output: output, command: '//error'
94
91
 
95
- if e.is_a?(ScriptError)
96
- send content: e.class.name
97
- send command: '//backtrace'
98
- send content: e.message
92
+ selected_backtrace_locations = e.backtrace_locations.select { |bt| bt.path == '(repl)' }
99
93
 
100
- elsif selected_backtrace_locations.empty?
101
- send content: "#{e.class.name}: #{e.message}"
102
- send command: '//backtrace'
103
- send content: e.backtrace_locations.first.to_s
94
+ if e.is_a?(ScriptError)
95
+ send output: output, content: e.class.name
96
+ send output: output, command: '//backtrace'
97
+ send output: output, content: e.message
104
98
 
105
- else
106
- lines = @block_source.split("\n")
99
+ elsif selected_backtrace_locations.empty?
100
+ send output: output, content: "#{e.class.name}: #{e.message}"
101
+ send output: output, command: '//backtrace'
102
+ send output: output, content: e.backtrace_locations.first.to_s
107
103
 
108
- lineno = selected_backtrace_locations.first.lineno
104
+ else
105
+ lines = @block_source.split("\n")
109
106
 
110
- source_before = lines[lineno - 2] if lineno >= 2
111
- source_error = lines[lineno - 1]
112
- source_after = lines[lineno]
107
+ lineno = selected_backtrace_locations.first.lineno
113
108
 
114
- send content: '***'
115
- send content: "[#{lineno - 1}] #{source_before}" if source_before
116
- send content: "[#{lineno}] #{source_error} \t\t<<< ERROR !!!"
117
- send content: "[#{lineno + 1}] #{source_after}" if source_after
118
- send content: '***'
119
- send content: e.class.name
120
- send content: e.message
121
- send command: '//backtrace'
122
- selected_backtrace_locations.each do |bt|
123
- send content: bt.to_s
109
+ source_before = lines[lineno - 2] if lineno >= 2
110
+ source_error = lines[lineno - 1]
111
+ source_after = lines[lineno]
112
+
113
+ send output: output, content: '***'
114
+ send output: output, content: "[#{lineno - 1}] #{source_before}" if source_before
115
+ send output: output, content: "[#{lineno}] #{source_error} \t\t<<< ERROR !!!"
116
+ send output: output, content: "[#{lineno + 1}] #{source_after}" if source_after
117
+ send output: output, content: '***'
118
+ send output: output, content: e.class.name
119
+ send output: output, content: e.message
120
+ send output: output, command: '//backtrace'
121
+ selected_backtrace_locations.each do |bt|
122
+ send output: output, content: bt.to_s
123
+ end
124
124
  end
125
+ send output: output, content: ' '
126
+ send output: output, command: '//end'
125
127
  end
126
- send content: ' '
127
- send command: '//end'
128
- end
129
128
 
130
- def send(content: nil, command: nil)
131
- puts escape(content) if content
132
- puts command if command
133
- end
129
+ def send(output:, content: nil, command: nil)
130
+ output.puts escape(content) if content
131
+ output.puts command if command
132
+ end
134
133
 
135
- def escape(text)
136
- if text.start_with? '//'
137
- "//#{text}"
138
- else
139
- text
134
+ def escape(text)
135
+ if text.start_with? '//'
136
+ "//#{text}"
137
+ else
138
+ text
139
+ end
140
140
  end
141
141
  end
142
142
  end