musa-dsl 0.14.31 → 0.21.4
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/.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 +31 -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 +554 -308
- 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: dae00405142514f16df2be12de1eb9327893f3996ad3c86ec76fc315db521e7d
|
4
|
+
data.tar.gz: f3ebf69b72452ab83ec33ab873221ee1f0d59954e2c67277c2386fc174278a7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 006f3143b93237b86600bde3b7229f14cae909a50603af4c0d1f33050835c582988325f8b2db63b74d20826d1682f09d51960e32d977f47ce86d69b4d25cd53b
|
7
|
+
data.tar.gz: 7c07575e0bcf7a2b5f9e6361d8ae2b64193b8bba31bec3badfbf02f8c83f8a3595bc84df42aa6c8976c947528c82752f9869ed7c19240c9d0d536cb435b4da86
|
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
|
+
|