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.
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 +187 -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 +122 -110
  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 +554 -308
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +75 -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 +89 -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 +111 -93
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0d0e02c2e0316db71806cd4a1370c6f7488d074c7f0c56f9debefa68e041d14
4
- data.tar.gz: 4d6e5c5f7dcd225ed5cb4f2f01129fa12a15be16253f5bfcb8cedf07c1bb6296
3
+ metadata.gz: dae00405142514f16df2be12de1eb9327893f3996ad3c86ec76fc315db521e7d
4
+ data.tar.gz: f3ebf69b72452ab83ec33ab873221ee1f0d59954e2c67277c2386fc174278a7c
5
5
  SHA512:
6
- metadata.gz: d7872920c8d0b01d28ea8359a7bccb84937820dcb1ce4cb98a158c351ac46f9e5a802d5986b6e7b584f3c527dd9be65e2df75d31dc5fa7394296dc2123ed4b5d
7
- data.tar.gz: a2dae59c40f1e713593a691e93ba989ee3aed3fe176b7da81e01aec579db83afc1c91d082c2915150249ab55a124c5f45f15fc99f506cc1cbdc3fb6a5d237d83
6
+ metadata.gz: 006f3143b93237b86600bde3b7229f14cae909a50603af4c0d1f33050835c582988325f8b2db63b74d20826d1682f09d51960e32d977f47ce86d69b4d25cd53b
7
+ data.tar.gz: 7c07575e0bcf7a2b5f9e6361d8ae2b64193b8bba31bec3badfbf02f8c83f8a3595bc84df42aa6c8976c947528c82752f9869ed7c19240c9d0d536cb435b4da86
data/.gitignore CHANGED
@@ -3,8 +3,10 @@
3
3
  .bundle
4
4
  .rspec
5
5
  .idea
6
+ .ruby-gemset
7
+ .ruby-version
6
8
  Gemfile.lock
7
9
  bin
8
10
  *.mindnode
9
-
11
+ test.musicxml
10
12
 
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  group :neuma do
4
4
  gem 'citrus', '~> 3.0.0'
5
-
6
5
  end
7
6
 
8
7
  group :transport do
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!
@@ -1,17 +1,60 @@
1
- require 'musa-dsl/core-ext'
1
+ module Musa
2
+ VERSION = '0.21.1'
3
+ end
2
4
 
3
- require 'musa-dsl/series'
4
- require 'musa-dsl/neuma'
5
- require 'musa-dsl/datasets'
5
+ require_relative 'musa-dsl/core-ext'
6
6
 
7
- require 'musa-dsl/neumalang'
7
+ require_relative 'musa-dsl/series'
8
+ require_relative 'musa-dsl/datasets'
9
+ require_relative 'musa-dsl/matrix'
8
10
 
9
- require 'musa-dsl/transport'
10
- require 'musa-dsl/sequencer'
11
- require 'musa-dsl/repl'
11
+ require_relative 'musa-dsl/neumalang'
12
+ require_relative 'musa-dsl/neumas'
12
13
 
13
- require 'musa-dsl/midi'
14
+ require_relative 'musa-dsl/logger'
14
15
 
15
- require 'musa-dsl/music'
16
+ require_relative 'musa-dsl/transport'
17
+ require_relative 'musa-dsl/sequencer'
18
+ require_relative 'musa-dsl/repl'
16
19
 
17
- require 'musa-dsl/generative'
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
@@ -1,13 +1,7 @@
1
- require 'musa-dsl/core-ext/array-apply-get'
2
- require 'musa-dsl/core-ext/array-explode-ranges'
3
- require 'musa-dsl/core-ext/array-to-serie'
4
- require 'musa-dsl/core-ext/string-to-neumas'
5
- require 'musa-dsl/core-ext/array-to-neumas'
6
- require 'musa-dsl/core-ext/arrayfy'
7
- require 'musa-dsl/core-ext/duplicate'
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
- class Array
2
- def arrayfy
3
- self
4
- end
5
-
6
- def repeat_to_size(new_size)
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
- new_array
14
- end
15
-
16
- def explode_ranges
17
- array = []
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
- each do |element|
20
- if element.is_a? Range
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
- class Object
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
- class Array
12
- def arrayfy
13
- self
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
+