musa-dsl 0.14.32 → 0.21.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/Gemfile +0 -1
- data/README.md +5 -1
- data/lib/musa-dsl.rb +54 -11
- data/lib/musa-dsl/core-ext.rb +7 -13
- data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
- data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
- data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
- data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
- data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
- data/lib/musa-dsl/core-ext/with.rb +26 -0
- data/lib/musa-dsl/datasets.rb +8 -3
- data/lib/musa-dsl/datasets/dataset.rb +3 -0
- data/lib/musa-dsl/datasets/delta-d.rb +12 -0
- data/lib/musa-dsl/datasets/e.rb +61 -0
- data/lib/musa-dsl/datasets/gdv.rb +51 -411
- data/lib/musa-dsl/datasets/gdvd.rb +179 -0
- data/lib/musa-dsl/datasets/helper.rb +41 -0
- data/lib/musa-dsl/datasets/p.rb +68 -0
- data/lib/musa-dsl/datasets/packed-v.rb +19 -0
- data/lib/musa-dsl/datasets/pdv.rb +22 -15
- data/lib/musa-dsl/datasets/ps.rb +113 -0
- data/lib/musa-dsl/datasets/score.rb +210 -0
- data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
- data/lib/musa-dsl/datasets/score/render.rb +31 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
- data/lib/musa-dsl/datasets/v.rb +23 -0
- data/lib/musa-dsl/generative.rb +5 -5
- data/lib/musa-dsl/generative/backboner.rb +274 -0
- data/lib/musa-dsl/generative/darwin.rb +102 -96
- data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
- data/lib/musa-dsl/generative/markov.rb +56 -53
- data/lib/musa-dsl/generative/variatio.rb +234 -222
- data/lib/musa-dsl/logger.rb +1 -0
- data/lib/musa-dsl/logger/logger.rb +32 -0
- data/lib/musa-dsl/matrix.rb +1 -0
- data/lib/musa-dsl/matrix/matrix.rb +210 -0
- data/lib/musa-dsl/midi.rb +2 -2
- data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
- data/lib/musa-dsl/midi/midi-voices.rb +187 -182
- data/lib/musa-dsl/music.rb +5 -5
- data/lib/musa-dsl/music/chord-definition.rb +54 -50
- data/lib/musa-dsl/music/chord-definitions.rb +13 -9
- data/lib/musa-dsl/music/chords.rb +236 -238
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
- data/lib/musa-dsl/music/scales.rb +331 -332
- data/lib/musa-dsl/musicxml.rb +1 -0
- data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
- data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
- data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
- data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
- data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
- data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
- data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
- data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
- data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
- data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
- data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
- data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
- data/lib/musa-dsl/neumalang.rb +1 -1
- data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
- data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
- data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
- data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
- data/lib/musa-dsl/neumalang/process.citrus +21 -0
- data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
- data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
- data/lib/musa-dsl/neumas.rb +5 -0
- data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
- data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
- data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
- data/lib/musa-dsl/neumas/neumas.rb +37 -0
- data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
- data/lib/musa-dsl/repl.rb +1 -1
- data/lib/musa-dsl/repl/repl.rb +122 -110
- data/lib/musa-dsl/sequencer.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +550 -321
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +75 -0
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
- data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
- data/lib/musa-dsl/series.rb +1 -1
- data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
- data/lib/musa-dsl/series/base-series.rb +171 -168
- data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
- data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
- data/lib/musa-dsl/series/proxy-serie.rb +6 -6
- data/lib/musa-dsl/series/queue-serie.rb +5 -5
- data/lib/musa-dsl/series/series.rb +2 -0
- data/lib/musa-dsl/transcription.rb +4 -0
- data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
- data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
- data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
- data/lib/musa-dsl/transcription/transcription.rb +55 -0
- data/lib/musa-dsl/transport.rb +6 -6
- data/lib/musa-dsl/transport/clock.rb +26 -26
- data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
- data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
- data/lib/musa-dsl/transport/input-midi-clock.rb +89 -80
- data/lib/musa-dsl/transport/timer-clock.rb +72 -71
- data/lib/musa-dsl/transport/timer.rb +28 -26
- data/lib/musa-dsl/transport/transport.rb +111 -93
- data/musa-dsl.gemspec +3 -3
- metadata +73 -24
- data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
- data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
- data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
- data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
- data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
- data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
- data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
- data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
- data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
- data/lib/musa-dsl/generative/rules.rb +0 -282
- data/lib/musa-dsl/neuma.rb +0 -1
- data/lib/musa-dsl/neuma/neuma.rb +0 -181
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46172601ed5c7fc82111b9ef5d669006f581e9ea4ebb0c36ef6c7108c9e0107e
|
4
|
+
data.tar.gz: aff0114b7c5a87e5e158eb5ff88882e0adfe4e39a8b7531f8aff323425e133f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 113e51f155961205cf92897802108124b1f953e7d2d690fcf11582d014c828af3ab13880ac6f69eefbd6fbdfca8d2eb9c96dfd507cd0bf42be87cdb654781753
|
7
|
+
data.tar.gz: b8a67793161526eff6a8be4dcd412da2d093228ff95b88c039973a5857da431b93e714b3e6d0d895462e6488a9368564c39b01ebaa6098c36ce7046269b20549
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
Work in progress.
|
4
4
|
|
5
|
-
A programming language DSL based on Ruby for musical composition.
|
5
|
+
A programming language DSL based on Ruby for sonic and musical composition.
|
6
6
|
Emphasizes the creation of complex temporal structures independently of the audio rendering engine.
|
7
7
|
|
8
8
|
Some works can be listened on [yeste.studio](https://soundcloud.com/yeste-studio) Soundcloud.
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
Coded on [Jetbrains RubyMine IDE](https://www.jetbrains.com/?from=Musa-DSL). Thanks a lot for your support letting me use an Open Source project free license!
|
data/lib/musa-dsl.rb
CHANGED
@@ -1,17 +1,60 @@
|
|
1
|
-
|
1
|
+
module Musa
|
2
|
+
VERSION = '0.21.1'
|
3
|
+
end
|
2
4
|
|
3
|
-
|
4
|
-
require 'musa-dsl/neuma'
|
5
|
-
require 'musa-dsl/datasets'
|
5
|
+
require_relative 'musa-dsl/core-ext'
|
6
6
|
|
7
|
-
|
7
|
+
require_relative 'musa-dsl/series'
|
8
|
+
require_relative 'musa-dsl/datasets'
|
9
|
+
require_relative 'musa-dsl/matrix'
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
require 'musa-dsl/repl'
|
11
|
+
require_relative 'musa-dsl/neumalang'
|
12
|
+
require_relative 'musa-dsl/neumas'
|
12
13
|
|
13
|
-
|
14
|
+
require_relative 'musa-dsl/logger'
|
14
15
|
|
15
|
-
|
16
|
+
require_relative 'musa-dsl/transport'
|
17
|
+
require_relative 'musa-dsl/sequencer'
|
18
|
+
require_relative 'musa-dsl/repl'
|
16
19
|
|
17
|
-
|
20
|
+
require_relative 'musa-dsl/midi'
|
21
|
+
require_relative 'musa-dsl/musicxml'
|
22
|
+
|
23
|
+
require_relative 'musa-dsl/transcription'
|
24
|
+
|
25
|
+
require_relative 'musa-dsl/music'
|
26
|
+
|
27
|
+
require_relative 'musa-dsl/generative'
|
28
|
+
|
29
|
+
module Musa::All
|
30
|
+
include Musa::Logger
|
31
|
+
|
32
|
+
include Musa::Clock
|
33
|
+
include Musa::Transport
|
34
|
+
include Musa::Sequencer
|
35
|
+
|
36
|
+
include Musa::Scales
|
37
|
+
include Musa::Chords
|
38
|
+
include Musa::Datasets
|
39
|
+
|
40
|
+
include Musa::Neumalang
|
41
|
+
include Musa::Neumas
|
42
|
+
include Musa::Matrix
|
43
|
+
|
44
|
+
include Musa::Series
|
45
|
+
|
46
|
+
include Musa::Darwin
|
47
|
+
include Musa::Markov
|
48
|
+
include Musa::Backboner
|
49
|
+
include Musa::Variatio
|
50
|
+
|
51
|
+
include Musa::MIDIRecorder
|
52
|
+
include Musa::MIDIVoices
|
53
|
+
|
54
|
+
include Musa::MusicXML
|
55
|
+
|
56
|
+
include Musa::Transcription
|
57
|
+
include Musa::Transcriptors
|
58
|
+
|
59
|
+
include Musa::REPL
|
60
|
+
end
|
data/lib/musa-dsl/core-ext.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require 'musa-dsl/core-ext/key-parameters-procedure-binder'
|
9
|
-
require 'musa-dsl/core-ext/as-context-run'
|
10
|
-
require 'musa-dsl/core-ext/inspect-nice'
|
11
|
-
require 'musa-dsl/core-ext/send-nice'
|
12
|
-
require 'musa-dsl/core-ext/proc-nice'
|
13
|
-
require 'musa-dsl/core-ext/dynamic-proxy'
|
1
|
+
require_relative 'core-ext/array-explode-ranges'
|
2
|
+
require_relative 'core-ext/arrayfy'
|
3
|
+
require_relative 'core-ext/deep-copy'
|
4
|
+
require_relative 'core-ext/smart-proc-binder'
|
5
|
+
require_relative 'core-ext/inspect-nice'
|
6
|
+
require_relative 'core-ext/dynamic-proxy'
|
7
|
+
require_relative 'core-ext/with'
|
@@ -1,29 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
pos = -1
|
8
|
-
new_size -= 1
|
9
|
-
|
10
|
-
new_array = clone
|
11
|
-
new_array << self[(pos += 1) % size] while (pos + size) < new_size
|
1
|
+
module Musa
|
2
|
+
module Extension
|
3
|
+
module ExplodeRanges
|
4
|
+
refine Array do
|
5
|
+
def explode_ranges
|
6
|
+
array = []
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
each do |element|
|
9
|
+
if element.is_a? Range
|
10
|
+
element.to_a.each { |element| array << element }
|
11
|
+
else
|
12
|
+
array << element
|
13
|
+
end
|
14
|
+
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
element.to_a.each { |element| array << element }
|
22
|
-
else
|
23
|
-
array << element
|
16
|
+
array
|
17
|
+
end
|
24
18
|
end
|
25
19
|
end
|
26
|
-
|
27
|
-
array
|
28
20
|
end
|
29
21
|
end
|
@@ -1,15 +1,33 @@
|
|
1
|
-
|
2
|
-
def arrayfy
|
3
|
-
if nil?
|
4
|
-
[]
|
5
|
-
else
|
6
|
-
[self]
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
1
|
+
require_relative 'deep-copy'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module Musa
|
4
|
+
module Extension
|
5
|
+
module Arrayfy
|
6
|
+
refine Object do
|
7
|
+
def arrayfy(size: nil)
|
8
|
+
if size
|
9
|
+
size.times.collect { self }
|
10
|
+
else
|
11
|
+
if nil?
|
12
|
+
[]
|
13
|
+
else
|
14
|
+
[self]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
refine Array do
|
21
|
+
def arrayfy(size: nil)
|
22
|
+
if size
|
23
|
+
DeepCopy::DeepCopy.copy_singleton_class_modules(
|
24
|
+
self,
|
25
|
+
(self * (size / self.size + ((size % self.size).zero? ? 0 : 1) )).take(size))
|
26
|
+
else
|
27
|
+
self.clone
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
14
32
|
end
|
15
33
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module Musa
|
2
|
+
module Extension
|
3
|
+
module AttributeBuilder
|
4
|
+
# add_thing id, parameter
|
5
|
+
# things id1: parameter1, id2: parameter2 -> { id1: Thing(id1, parameter1), id2: Thing(id2, parameter2) }
|
6
|
+
# things -> { id1: Thing(id1, parameter1), id2: Thing(id2, parameter2) }
|
7
|
+
#
|
8
|
+
def attr_tuple_adder_to_hash(name, klass, plural: nil, variable: nil)
|
9
|
+
|
10
|
+
plural ||= name.to_s + 's'
|
11
|
+
variable ||= ('@' + plural.to_s).to_sym
|
12
|
+
|
13
|
+
adder_method = "add_#{name}".to_sym
|
14
|
+
|
15
|
+
define_method adder_method do |id, parameter|
|
16
|
+
klass.new(id, parameter).tap do |object|
|
17
|
+
instance_variable_get(variable)[id] = object
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
define_method plural do |**parameters|
|
22
|
+
parameters&.each_pair do |id, value|
|
23
|
+
send adder_method, id, value
|
24
|
+
end
|
25
|
+
instance_variable_get variable
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# add_thing id, parameter
|
30
|
+
# things id1: parameter1, id2: parameter2 -> [ Thing(id1, parameter1), Thing(id2, parameter2) ]
|
31
|
+
# things -> [ Thing(id1, parameter1), Thing(id2, parameter2) ]
|
32
|
+
|
33
|
+
def attr_tuple_adder_to_array(name, klass, plural: nil, variable: nil)
|
34
|
+
|
35
|
+
plural ||= name.to_s + 's'
|
36
|
+
variable ||= ('@' + plural.to_s).to_sym
|
37
|
+
|
38
|
+
adder_method = "add_#{name}".to_sym
|
39
|
+
|
40
|
+
define_method adder_method do |id, parameter, &block|
|
41
|
+
klass.new(id, parameter, &block).tap do |object|
|
42
|
+
instance_variable_get(variable) << object
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method plural do |**parameters, &block|
|
47
|
+
parameters.each_pair do |id, value|
|
48
|
+
send adder_method, id, value, &block
|
49
|
+
end
|
50
|
+
instance_variable_get variable
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# add_thing param1, param2, key1: parameter1, key2: parameter2 -> Thing(...)
|
55
|
+
# thing param1, param2, key1: parameter1, key2: parameter2 -> Thing(...)
|
56
|
+
# things -> (collection)
|
57
|
+
|
58
|
+
def attr_complex_adder_to_array(name, klass, plural: nil, variable: nil)
|
59
|
+
|
60
|
+
plural ||= name.to_s + 's'
|
61
|
+
variable ||= ('@' + plural.to_s).to_sym
|
62
|
+
|
63
|
+
adder_method = "add_#{name}".to_sym
|
64
|
+
|
65
|
+
define_method adder_method do |*parameters, **key_parameters, &block|
|
66
|
+
klass.new(*parameters, **key_parameters, &block).tap do |object|
|
67
|
+
instance_variable_get(variable) << object
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if plural == name
|
72
|
+
define_method plural do |*parameters, **key_parameters, &block|
|
73
|
+
if parameters.empty? && key_parameters.empty? && block.nil?
|
74
|
+
instance_variable_get variable
|
75
|
+
else
|
76
|
+
send adder_method, *parameters, **key_parameters, &block
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
alias_method name, adder_method
|
81
|
+
|
82
|
+
define_method plural do
|
83
|
+
instance_variable_get variable
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# add_thing param1, param2, key1: parameter1, key2: parameter2 -> Thing(...)
|
90
|
+
# thing param1, param2, key1: parameter1, key2: parameter2 -> Thing(...)
|
91
|
+
# things -> (collection)
|
92
|
+
|
93
|
+
def attr_complex_adder_to_custom(name, plural: nil, variable: nil, &constructor_and_adder)
|
94
|
+
|
95
|
+
plural ||= name.to_s + 's'
|
96
|
+
|
97
|
+
adder_method = "add_#{name}".to_sym
|
98
|
+
|
99
|
+
define_method adder_method do |*parameters, **key_parameters, &block|
|
100
|
+
instance_exec(*parameters, **key_parameters, &constructor_and_adder).tap do |object|
|
101
|
+
object.with &block if block
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if plural == name && variable
|
106
|
+
define_method plural do |*parameters, **key_parameters, &block|
|
107
|
+
if parameters.empty? && key_parameters.empty? && block.nil?
|
108
|
+
instance_variable_get variable
|
109
|
+
else
|
110
|
+
send adder_method, *parameters, **key_parameters, &block
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else
|
114
|
+
alias_method name, adder_method
|
115
|
+
|
116
|
+
if variable
|
117
|
+
define_method plural do
|
118
|
+
instance_variable_get variable
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# thing value -> crea Thing(value)
|
125
|
+
# thing -> Thing(value)
|
126
|
+
|
127
|
+
def attr_simple_builder(name, klass = nil, variable: nil)
|
128
|
+
variable ||= ('@' + name.to_s).to_sym
|
129
|
+
|
130
|
+
define_method name do |parameter = nil, &block|
|
131
|
+
if parameter.nil?
|
132
|
+
instance_variable_get variable
|
133
|
+
else
|
134
|
+
(klass&.new(parameter, &block) || parameter).tap do |object|
|
135
|
+
instance_variable_set variable, object
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
attr_writer name
|
141
|
+
end
|
142
|
+
|
143
|
+
# thing id: value -> crea Thing(id, value)
|
144
|
+
# thing -> Thing(id, value)
|
145
|
+
|
146
|
+
def attr_tuple_builder(name, klass, variable: nil)
|
147
|
+
variable ||= ('@' + name.to_s).to_sym
|
148
|
+
|
149
|
+
define_method name do |**parameters, &block|
|
150
|
+
raise ArgumentError, "Method #{name} can only create instances with one id: value arguments pattern" unless parameters.size == 1
|
151
|
+
|
152
|
+
if parameters.empty?
|
153
|
+
instance_variable_get variable
|
154
|
+
else
|
155
|
+
parameter = parameters.first
|
156
|
+
klass.new(*parameter, &block).tap do |object|
|
157
|
+
instance_variable_set variable, object
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
attr_writer name
|
163
|
+
end
|
164
|
+
|
165
|
+
# thing value1, value2, key1: value3, key2: value4 -> crea Thing(value1, value2, key1: value3, key2: value3)
|
166
|
+
# thing -> Thing(value1, value2, key1: value3, key2: value4)
|
167
|
+
# y también...
|
168
|
+
# thing value1, value2, key1: value3, key2: value4 -> crea Thing(first_parameter, value1, value2, key1: value3, key2: value3)
|
169
|
+
# thing -> Thing(first_parameter, value1, value2, key1: value3, key2: value4)
|
170
|
+
|
171
|
+
def attr_complex_builder(name, klass, variable: nil, first_parameter: nil)
|
172
|
+
variable ||= ('@' + name.to_s).to_sym
|
173
|
+
|
174
|
+
define_method name do |*parameters, **key_parameters, &block|
|
175
|
+
if parameters.empty? && key_parameters.empty? && block.nil?
|
176
|
+
instance_variable_get variable
|
177
|
+
else
|
178
|
+
if first_parameter
|
179
|
+
klass.new(first_parameter, *parameters, **key_parameters, &block).tap do |object|
|
180
|
+
instance_variable_set variable, object
|
181
|
+
end
|
182
|
+
else
|
183
|
+
klass.new(*parameters, **key_parameters, &block).tap do |object|
|
184
|
+
instance_variable_set variable, object
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
attr_writer name
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# Based on https://github.com/adamluzsi/duplicate.rb/blob/master/lib/duplicate.rb
|
2
|
+
# Modifications by Javier Sánchez Yeste
|
3
|
+
|
4
|
+
module Musa
|
5
|
+
module Extension
|
6
|
+
module DeepCopy
|
7
|
+
module DeepCopy
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def deep_copy(object, method: :dup, freeze: true)
|
11
|
+
raise ArgumentError, "deep_copy method can only be :dup or :clone" unless method == :dup || method == :clone
|
12
|
+
register = {}
|
13
|
+
|
14
|
+
_deep_copy(register, object, method, freeze)
|
15
|
+
end
|
16
|
+
|
17
|
+
def copy_singleton_class_modules(source, target)
|
18
|
+
source.singleton_class.included_modules.each do |m|
|
19
|
+
target.extend m unless target.is_a?(m)
|
20
|
+
end
|
21
|
+
|
22
|
+
target
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def registered(object, register)
|
28
|
+
register[object.__id__]
|
29
|
+
end
|
30
|
+
|
31
|
+
def register(register, object, duplicate)
|
32
|
+
register[object.__id__] = duplicate
|
33
|
+
duplicate
|
34
|
+
end
|
35
|
+
|
36
|
+
def _deep_copy(register, object, method, freeze)
|
37
|
+
return registered(object, register) if registered(object, register)
|
38
|
+
return register(register, object, object) unless identifiable?(object)
|
39
|
+
|
40
|
+
case object
|
41
|
+
|
42
|
+
when Array
|
43
|
+
deep_copy_array(register, object, method, freeze)
|
44
|
+
|
45
|
+
when Hash
|
46
|
+
deep_copy_hash(register, object, method, freeze)
|
47
|
+
|
48
|
+
when Range
|
49
|
+
deep_copy_range(register, object, method, freeze)
|
50
|
+
|
51
|
+
when Struct
|
52
|
+
deep_copy_struct(register, object, method, freeze)
|
53
|
+
|
54
|
+
when Proc
|
55
|
+
deep_copy_proc(register, object, method, freeze)
|
56
|
+
|
57
|
+
when NilClass, Symbol, Numeric, TrueClass, FalseClass, Method
|
58
|
+
register(register, object, object)
|
59
|
+
|
60
|
+
else
|
61
|
+
deep_copy_object(register, object, method, freeze)
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def identifiable?(object)
|
67
|
+
object.class && object.respond_to?(:is_a?)
|
68
|
+
rescue NoMethodError
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
def deep_copy_array(register, object, method, freeze)
|
73
|
+
deep_copy_object(register, object, method, freeze) do |_, copy|
|
74
|
+
copy.map! { |e| _deep_copy(register, e, method, freeze) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def deep_copy_hash(register, object, method, freeze)
|
79
|
+
deep_copy_object(register, object, method, freeze) do |object, copy|
|
80
|
+
object.reduce(copy) { |hash, (k, v)| hash.merge!(_deep_copy(register, k, method, freeze) => _deep_copy(register, v, method, freeze)) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def deep_copy_range(register, range, method, freeze)
|
85
|
+
copy = range.class.new(_deep_copy(register, range.first, method, freeze), _deep_copy(register, range.last, method, freeze))
|
86
|
+
copy.freeze if range.frozen?
|
87
|
+
|
88
|
+
register(register, range, copy)
|
89
|
+
rescue StandardError
|
90
|
+
register(register, range, range.send(method))
|
91
|
+
end
|
92
|
+
|
93
|
+
def deep_copy_struct(register, struct, method, freeze)
|
94
|
+
duplication = register(register, struct, struct.send(method))
|
95
|
+
|
96
|
+
struct.each_pair do |attr, value|
|
97
|
+
duplication.__send__("#{attr}=", _deep_copy(register, value, method, freeze))
|
98
|
+
end
|
99
|
+
|
100
|
+
duplication
|
101
|
+
end
|
102
|
+
|
103
|
+
def deep_copy_object(register, object, method, freeze)
|
104
|
+
if method == :clone && object.frozen?
|
105
|
+
copy = try_deep_copy(object, :clone, false)
|
106
|
+
else
|
107
|
+
copy = try_deep_copy(object, method, freeze)
|
108
|
+
end
|
109
|
+
|
110
|
+
register(register, object, copy)
|
111
|
+
deep_copy_instance_variables(register, object, register(register, object, copy), method, freeze)
|
112
|
+
|
113
|
+
yield object, copy if block_given?
|
114
|
+
|
115
|
+
copy.freeze if method == :clone && object.frozen? && freeze
|
116
|
+
|
117
|
+
copy
|
118
|
+
end
|
119
|
+
|
120
|
+
def deep_copy_proc(register, object, method, freeze)
|
121
|
+
register(register, object, object.dup)
|
122
|
+
end
|
123
|
+
|
124
|
+
def deep_copy_instance_variables(register, object, duplication, method, freeze)
|
125
|
+
return duplication unless respond_to_instance_variables?(object)
|
126
|
+
|
127
|
+
object.instance_variables.each do |instance_variable|
|
128
|
+
value = get_instance_variable(object, instance_variable)
|
129
|
+
|
130
|
+
set_instance_variable(duplication, instance_variable, _deep_copy(register, value, method, freeze))
|
131
|
+
end
|
132
|
+
|
133
|
+
duplication
|
134
|
+
end
|
135
|
+
|
136
|
+
def get_instance_variable(object, instance_variable_name)
|
137
|
+
object.instance_variable_get(instance_variable_name)
|
138
|
+
rescue NoMethodError
|
139
|
+
object.instance_eval(instance_variable_name.to_s)
|
140
|
+
end
|
141
|
+
|
142
|
+
def set_instance_variable(duplicate, instance_variable_name, value_to_set)
|
143
|
+
duplicate.instance_variable_set(instance_variable_name, value_to_set)
|
144
|
+
rescue NoMethodError
|
145
|
+
duplicate.instance_eval("#{instance_variable_name} = Marshal.load(#{Marshal.dump(value_to_set).inspect})")
|
146
|
+
end
|
147
|
+
|
148
|
+
def try_deep_copy(object, method, freeze)
|
149
|
+
if method == :dup
|
150
|
+
object.dup
|
151
|
+
else
|
152
|
+
object.clone(freeze: freeze)
|
153
|
+
end
|
154
|
+
rescue NoMethodError, TypeError
|
155
|
+
object
|
156
|
+
end
|
157
|
+
|
158
|
+
def respond_to_instance_variables?(object)
|
159
|
+
object.respond_to?(:instance_variables) && object.instance_variables.is_a?(Array)
|
160
|
+
rescue NoMethodError
|
161
|
+
false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
refine Object do
|
166
|
+
def dup(deep: false)
|
167
|
+
if deep
|
168
|
+
Musa::Extension::DeepCopy::DeepCopy.deep_copy(self, method: :dup)
|
169
|
+
else
|
170
|
+
super()
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def clone(freeze: true, deep: false)
|
175
|
+
if deep
|
176
|
+
Musa::Extension::DeepCopy::DeepCopy.deep_copy(self, method: :clone, freeze: freeze)
|
177
|
+
else
|
178
|
+
super(freeze: freeze)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|