ryo.rb 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/specs.yml +23 -0
  3. data/.gitignore +6 -0
  4. data/.gitlab-ci.yml +9 -0
  5. data/.rubocop.yml +56 -0
  6. data/.yardoc-template/default/fulldoc/html/css/0x1eef.css +15 -0
  7. data/.yardoc-template/default/layout/html/setup.rb +5 -0
  8. data/.yardoc-template/default/module/setup.rb +7 -0
  9. data/.yardopts +4 -0
  10. data/Gemfile +5 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +373 -0
  13. data/Rakefile +3 -0
  14. data/lib/ryo/basic_object.rb +58 -0
  15. data/lib/ryo/builder.rb +106 -0
  16. data/lib/ryo/enumerable.rb +214 -0
  17. data/lib/ryo/function.rb +68 -0
  18. data/lib/ryo/keywords.rb +67 -0
  19. data/lib/ryo/lazy.rb +4 -0
  20. data/lib/ryo/object.rb +58 -0
  21. data/lib/ryo/reflect.rb +379 -0
  22. data/lib/ryo/version.rb +5 -0
  23. data/lib/ryo.rb +197 -0
  24. data/ryo.rb.gemspec +21 -0
  25. data/share/ryo.rb/examples/1.0_prototypes_point_object.rb +12 -0
  26. data/share/ryo.rb/examples/1.1_prototypes_ryo_fn.rb +14 -0
  27. data/share/ryo.rb/examples/2.0_iteration_each.rb +13 -0
  28. data/share/ryo.rb/examples/2.1_iteration_map.rb +16 -0
  29. data/share/ryo.rb/examples/2.2_iteration_ancestors.rb +13 -0
  30. data/share/ryo.rb/examples/3.0_recursion_ryo_from.rb +13 -0
  31. data/share/ryo.rb/examples/3.1_recursion_ryo_from_with_array.rb +19 -0
  32. data/share/ryo.rb/examples/3.2_recursion_ryo_from_with_openstruct.rb +14 -0
  33. data/share/ryo.rb/examples/4.0_basicobject_ryo_basicobject.rb +12 -0
  34. data/share/ryo.rb/examples/4.1_basicobject_ryo_basicobject_from.rb +13 -0
  35. data/share/ryo.rb/examples/5_collisions_resolution_strategy.rb +8 -0
  36. data/share/ryo.rb/examples/6_beyond_hash_objects.rb +20 -0
  37. data/share/ryo.rb/examples/7_ryo_lazy.rb +14 -0
  38. data/share/ryo.rb/examples/setup.rb +3 -0
  39. data/spec/readme_spec.rb +79 -0
  40. data/spec/ryo_basic_object_spec.rb +60 -0
  41. data/spec/ryo_enumerable_spec.rb +197 -0
  42. data/spec/ryo_keywords_spec.rb +86 -0
  43. data/spec/ryo_object_spec.rb +71 -0
  44. data/spec/ryo_prototypes_spec.rb +45 -0
  45. data/spec/ryo_reflect_spec.rb +175 -0
  46. data/spec/ryo_spec.rb +130 -0
  47. data/spec/setup.rb +5 -0
  48. metadata +173 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 61ffcab409332ea4c6979e302c9d27f467575ef2b8167f07805e7f20ad523002
4
+ data.tar.gz: fb5f3050e9a373616e377a5d76c0605f7ce6e655ca8a2822619dd63d7426182d
5
+ SHA512:
6
+ metadata.gz: 1158833ffda85f18fabdb7f7830fe0a104f91bfe5d19d2f0d8a21e51ac5d95d34dd6744d100b0ba6e0c5c6ece7ecdd38a80f59f2ceb55898403d490de9be14b6
7
+ data.tar.gz: c92c24f793503360539dc314c1c15d9349f23efee1cc29ca9af2dab497528d1b7186f77ee839f7ce36592c223ae6a4b8bdd058cb00091361a098268bad0e5af3
@@ -0,0 +1,23 @@
1
+ name: Ryo specs
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ specs:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest]
15
+ ruby: [3.1, 3.2]
16
+ runs-on: ${{ matrix.os }}
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - run: bundle install
23
+ - run: rspec -Ilib -rryo spec/
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ doc/
2
+ .*rc
3
+ .*_history
4
+ .yardoc
5
+ *.lock
6
+ pkg/
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,9 @@
1
+ stages:
2
+ - test
3
+
4
+ test-ruby32:
5
+ stage: test
6
+ image: ruby:3.2.1
7
+ script:
8
+ - bundle install
9
+ - bundle exec rspec spec/
data/.rubocop.yml ADDED
@@ -0,0 +1,56 @@
1
+ ##
2
+ # Plugins
3
+ require:
4
+ - standard
5
+ - rubocop-rspec
6
+
7
+ ##
8
+ # Defaults: standard-rb
9
+ inherit_gem:
10
+ standard: config/base.yml
11
+
12
+ ##
13
+ # Enabled cops
14
+ Style/FrozenStringLiteralComment:
15
+ Enabled: true
16
+
17
+ ##
18
+ # Disabled cops
19
+ Layout/MultilineMethodCallIndentation:
20
+ Enabled: false
21
+ Style/LambdaCall:
22
+ Enabled: false
23
+ Lint/AssignmentInCondition:
24
+ Enabled: false
25
+
26
+ ##
27
+ # Disabled cops (rspec)
28
+ RSpec/FilePath:
29
+ Enabled: false
30
+ RSpec/NestedGroups:
31
+ Enabled: false
32
+ RSpec/NotToNot:
33
+ Enabled: false
34
+ RSpec/EmptyLineAfterHook:
35
+ Enabled: false
36
+ RSpec/EmptyLineAfterSubject:
37
+ Enabled: false
38
+ RSpec/DescribedClass:
39
+ Enabled: false
40
+ RSpec/MultipleExpectations:
41
+ Enabled: false
42
+ RSpec/EmptyLineAfterFinalLet:
43
+ Enabled: false
44
+ Style/NilComparison:
45
+ Exclude:
46
+ - spec/ryo_object_spec.rb
47
+ RSpec/DescribeClass:
48
+ Enabled: false
49
+
50
+ AllCops:
51
+ Include:
52
+ - 'lib/*.rb'
53
+ - 'lib/**/*.rb'
54
+ - 'spec/*.rb'
55
+ - 'spec/**/*.rb'
56
+ TargetRubyVersion: 3.2
@@ -0,0 +1,15 @@
1
+ #main #content #filecontents p, .discussion p, ul.param li, div.note {
2
+ max-width: 768px;
3
+ }
4
+
5
+ #toc {
6
+ position: fixed;
7
+ right: 25px;
8
+ display: none;
9
+ }
10
+
11
+ @media screen and (min-width: 1280px) {
12
+ #toc {
13
+ display: block;
14
+ }
15
+ }
@@ -0,0 +1,5 @@
1
+ def stylesheets
2
+ s = super
3
+ s << "css/0x1eef.css"
4
+ s
5
+ end
@@ -0,0 +1,7 @@
1
+ ##
2
+ # Sort methods in ascending order based
3
+ # on the line number where a method is
4
+ # defined.
5
+ def sort_listing(listing)
6
+ listing.sort_by { _1.files[1] }
7
+ end
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ -m markdown -M redcarpet --hide-void-return --no-private -t default -p .yardoc-template
2
+ -
3
+ README.md
4
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gem "test-cmd.rb", github: "0x1eef/test-cmd.rb", tag: "v0.4.0"
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright 2022
4
+ 0x1eef
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,373 @@
1
+ ## About
2
+
3
+ Ryo implements prototype-based inheritance, in Ruby.
4
+
5
+ Ryo's implementation of prototype-based inheritance offers
6
+ a flexible approach for establishing object relationships,
7
+ and building configuration objects. Ryo can also act as a
8
+ recursive OpenStruct alternative. JavaScript's implementation of
9
+ prototype-based inheritance served as a reference point
10
+ for Ryo's implementation.
11
+
12
+ ## Examples
13
+
14
+ ### Prototypes
15
+
16
+ #### Point object
17
+
18
+ The following example demonstrates how prototype-based inheritance is
19
+ implemented in Ryo. The example introduces three objects to form a
20
+ single point object with the properties, "x" and "y". The
21
+ [Ryo()](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method)
22
+ method seen in the example returns an instance of
23
+ [Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html):
24
+
25
+ ```ruby
26
+ require "ryo"
27
+
28
+ point_x = Ryo(x: 5)
29
+ point_y = Ryo({y: 10}, point_x)
30
+ point = Ryo({}, point_y)
31
+ p [point.x, point.y]
32
+
33
+ ##
34
+ # [5, 10]
35
+ ```
36
+
37
+ #### Ryo.fn
38
+
39
+ The following example demonstrates a Ryo function.
40
+ [`Ryo.fn`](https://0x1eef.github.io/x/ryo.rb/Ryo/Keywords.html#function-instance_method)
41
+ will bind its `self` to the Ryo object it is assigned to, and when the function
42
+ is called it will have access to the properties of the Ryo object:
43
+
44
+ ```ruby
45
+ require "ryo"
46
+
47
+ point_x = Ryo(x: 5)
48
+ point_y = Ryo({y: 10}, point_x)
49
+ point = Ryo({
50
+ multiply: Ryo.fn { |m| [x * m, y * m] }
51
+ }, point_y)
52
+ p point.multiply.call(2)
53
+
54
+ ##
55
+ # [10, 20]
56
+ ```
57
+
58
+ #### Ryo.lazy
59
+
60
+ The following example demonstrates a lazy Ryo value.
61
+ [`Ryo.lazy`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#lazy-class_method)
62
+ creates a lazy value that is not evaluated until a property is accessed
63
+ for the first time. It is similar to a Ryo function but it does not require
64
+ that the `#call` method be used, and after the property is accessed for the
65
+ first time the lazy value is replaced by the evaluated value:
66
+
67
+ ```ruby
68
+ require "ryo"
69
+
70
+ point_x = Ryo(x: Ryo.lazy { 5 })
71
+ point_y = Ryo({y: Ryo.lazy { 10 }}, point_x)
72
+ point = Ryo({sum: Ryo.lazy { x + y }}, point_y)
73
+ print "point.x = ", point.x, "\n"
74
+ print "point.y = ", point.y, "\n"
75
+ print "point.sum = ", point.sum, "\n"
76
+
77
+ ##
78
+ # point.x = 5
79
+ # point.y = 10
80
+ # point.sum = 15
81
+ ```
82
+
83
+
84
+ ### Iteration
85
+
86
+ #### Ryo.each
87
+
88
+ The
89
+ [`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method)
90
+ method can iterate through the properties of a Ryo object, and
91
+ its prototype(s). Ryo is designed to not mix its implementation
92
+ with the objects it creates - that's why
93
+ [`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method)
94
+ is not implemented directly on a Ryo object.
95
+
96
+ A demonstration of [`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method):
97
+
98
+ ```ruby
99
+ require "ryo"
100
+
101
+ point = Ryo(x: 10, y: 20)
102
+ Ryo.each(point) do |key, value|
103
+ p [key, value]
104
+ end
105
+
106
+ ##
107
+ # ["x", 10]
108
+ # ["y", 20]
109
+ ```
110
+
111
+ #### Ryo.map!
112
+
113
+ [`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
114
+ methods can return a new copy of a Ryo object and its prototypes, or mutate
115
+ a Ryo object and its prototypes in-place. The following example demonstrates
116
+ an in-place map operation on a Ryo object with
117
+ [`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method).
118
+ The counterpart of
119
+ [`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method)
120
+ is
121
+ [`Ryo.map`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map-instance_method),
122
+ and it returns a new copy of a Ryo object and its prototypes.
123
+
124
+ A demonstration of [`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method):
125
+
126
+ ```ruby
127
+ require "ryo"
128
+
129
+ point_x = Ryo(x: 2)
130
+ point_y = Ryo({y: 4}, point_x)
131
+ point = Ryo({}, point_y)
132
+
133
+ Ryo.map!(point) { |key, value| value * 2 }
134
+ p [point.x, point.y]
135
+ p [point_x.x, point_y.y]
136
+
137
+ ##
138
+ # [4, 8]
139
+ # [4, 8]
140
+ ```
141
+
142
+ #### Ancestors
143
+
144
+ All [`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
145
+ methods support an optional `ancestors` option.
146
+
147
+ `ancestors` is an integer that determines how far up the prototype chain a
148
+ [`Ryo::Enumerable`](https://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
149
+ method can go. 0 covers a Ryo object, and none of the prototypes in its
150
+ prototype chain. 1 covers a Ryo object, and one of the prototypes in its
151
+ prototype chain - and so on.
152
+
153
+ When the `ancestors` option is not provided, the default behavior of
154
+ [`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
155
+ methods is to traverse the entire prototype chain. The following example
156
+ demonstrates using the `ancestors` option with
157
+ [`Ryo.find`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#find-class_method):
158
+
159
+ ```ruby
160
+ require "ryo"
161
+
162
+ point_x = Ryo(x: 5)
163
+ point_y = Ryo({y: 10}, point_x)
164
+ point = Ryo({}, point_y)
165
+
166
+ p Ryo.find(point, ancestors: 0) { |k,v| v == 5 } # => nil
167
+ p Ryo.find(point, ancestors: 1) { |k,v| v == 5 } # => nil
168
+ p Ryo.find(point, ancestors: 2) { |k,v| v == 5 }.x # => point_x.x
169
+ p Ryo.find(point) { |k,v| v == 5 }.x # => point_x.x
170
+ ```
171
+
172
+ ### Recursion
173
+
174
+ #### Ryo.from
175
+
176
+ The [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method) method has
177
+ the same interface as the [`Ryo`](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method)
178
+ method, but it is implemented to recursively walk a Hash object and create Ryo objects
179
+ from other Hash objects found along the way. Recursion is not the default behavior
180
+ because it has the potential to be slow when given a complex Hash object that's
181
+ very large - otherwise there shouldn't be a noticeable performance impact.
182
+
183
+ The following example demonstrates [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method):
184
+
185
+ ```ruby
186
+ require "ryo"
187
+
188
+ point = Ryo.from({
189
+ x: {to_i: 0},
190
+ y: {to_i: 10}
191
+ })
192
+ p [point.x.to_i, point.y.to_i]
193
+
194
+ ##
195
+ # [0, 10]
196
+ ```
197
+
198
+ #### Ryo.from with an Array
199
+
200
+ The [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method) method can
201
+ walk an Array object, and create Ryo objects from Hash objects found along the way.
202
+ An object that can't be turned into a Ryo object is left as-is. The following
203
+ example demonstrates how that works in practice:
204
+
205
+ ``` ruby
206
+ require "ryo"
207
+
208
+ points = Ryo.from([
209
+ {x: {to_i: 2}},
210
+ "foobar",
211
+ {y: {to_i: 4}}
212
+ ])
213
+
214
+ p points[0].x.to_i
215
+ p points[1]
216
+ p points[2].y.to_i
217
+
218
+ ##
219
+ # 2
220
+ # "foobar"
221
+ # 4
222
+ ```
223
+
224
+ #### Ryo.from with OpenStruct
225
+
226
+ All methods that can create Ryo objects support turning a Struct, or OpenStruct object
227
+ into a Ryo object. The following example demonstrates how
228
+ [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method)
229
+ can recursively turn an OpenStruct object into Ryo objects. The example also assigns
230
+ a prototype to the Ryo object created from the OpenStruct:
231
+
232
+ ``` ruby
233
+ require "ryo"
234
+ require "ostruct"
235
+
236
+ point = Ryo.from(
237
+ OpenStruct.new(x: {to_i: 5}),
238
+ Ryo.from(y: {to_i: 10})
239
+ )
240
+ p [point.x.to_i, point.y.to_i]
241
+
242
+ ##
243
+ # [5, 10]
244
+ ```
245
+
246
+ ### BasicObject
247
+
248
+ #### Ryo::BasicObject
249
+
250
+ All of the previous examples have been working with instances of
251
+ [Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html),
252
+ a subclass of Ruby's Object class. In comparison, [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html) -
253
+ a subclass of Ruby's BasicObject class, provides an object
254
+ with fewer methods. The following example demonstrates
255
+ how to create an instance of [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html):
256
+
257
+ ```ruby
258
+ require "ryo"
259
+
260
+ point_x = Ryo::BasicObject(x: 0)
261
+ point_y = Ryo::BasicObject({y: 0}, point_x)
262
+ point = Ryo::BasicObject({}, point_y)
263
+ p [point.x, point.y]
264
+
265
+ ##
266
+ # [0, 0]
267
+ ```
268
+
269
+ #### Ryo::BasicObject.from
270
+
271
+ [Ryo::BasicObject.from](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html#from-class_method)
272
+ is identical to Ryo.from but rather than returning instance(s) of [Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html)
273
+ it returns instance(s) of [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html)
274
+ instead:
275
+
276
+ ```ruby
277
+ require "ryo"
278
+
279
+ point = Ryo::BasicObject.from({
280
+ x: {to_i: 2},
281
+ y: {to_i: 4}
282
+ })
283
+ p [point.x.to_i, point.y.to_i]
284
+
285
+ ##
286
+ # [2, 4]
287
+ ```
288
+
289
+ ### Collisions
290
+
291
+ #### Resolution strategy
292
+
293
+ When a property and method collide, Ryo tries to find the best resolution. Since Ryo properties
294
+ don't accept arguments, and methods can - we are able to distinguish a property from a method in
295
+ many cases.
296
+
297
+ Consider this example, where a property collides with the `Kernel#then` method. This example
298
+ would work the same for other methods that accept a block and/or arguments:
299
+
300
+ ```ruby
301
+ require "ryo"
302
+
303
+ ryo = Ryo::Object(then: 12)
304
+ p ryo.then # => 12
305
+ p ryo.then { 34 } # => 34
306
+ ```
307
+
308
+ ### Beyond Hash objects
309
+
310
+ #### Duck typing
311
+
312
+ The documentation has used simple terms to describe the objects that Ryo works
313
+ with: Hash and Array objects. But actually, Ryo uses duck typing, so any object
314
+ that implements `#each_pair` can be treated as a Hash object, and any object that
315
+ implements `#each` can be treated as an Array object. Note that only
316
+ [Ryo.from](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method),
317
+ [Ryo::Object.from](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html#from-class_method)
318
+ and
319
+ [Ryo::BasicObject.from](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html#from-class_method)
320
+ can handle Array/#each objects.
321
+
322
+ Here's an example of how to turn your own custom object, which implements
323
+ `#each_pair`, into a Ryo object:
324
+
325
+ ``` ruby
326
+ require "ryo"
327
+
328
+ class Point
329
+ def initialize
330
+ @x = 5
331
+ @y = 10
332
+ end
333
+
334
+ def each_pair
335
+ yield("x", @x)
336
+ yield("y", @y)
337
+ end
338
+ end
339
+
340
+ point = Ryo(Point.new)
341
+ p point.x # => 5
342
+ p point.y # => 10
343
+ ```
344
+
345
+ ## Sources
346
+
347
+ * [Source code (GitHub)](https://github.com/0x1eef/ryo.rb#readme)
348
+ * [Source code (GitLab)](https://gitlab.com/0x1eef/ryo.rb#about)
349
+
350
+ ## <a id='install'>Install</a>
351
+
352
+ Ryo is distributed as a RubyGem through its git repositories. <br>
353
+ [GitHub](https://github.com/0x1eef/ryo.rb),
354
+ and
355
+ [GitLab](https://gitlab.com/0x1eef/ryo.rb)
356
+ are available as sources.
357
+
358
+ **Gemfile**
359
+
360
+ ```ruby
361
+ gem "ryo.rb", github: "0x1eef/ryo.rb", tag: "v0.4.4"
362
+ ```
363
+
364
+ ## Thanks
365
+
366
+ Thanks to
367
+ [@awfulcooking (mooff)](https://github.com/awfulcooking)
368
+ for the helpful discussions and advice.
369
+
370
+ ## License
371
+
372
+ This project is released under the terms of the MIT license. <br>
373
+ See [./LICENSE.txt](./LICENSE.txt) for details.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # {Ryo::BasicObject Ryo::BasicObject} is a Ryo object and subclass
5
+ # of Ruby's BasicObject class that can be created by using
6
+ # {Ryo.BasicObject Ryo.BasicObject()},
7
+ # {Ryo::BasicObject.from Ryo::BasicObject.from}, or
8
+ # {Ryo::BasicObject.create Ryo::BasicObject.create}.
9
+ class Ryo::BasicObject < BasicObject
10
+ ##
11
+ # @param props (see Ryo::Builder.build)
12
+ # @param prototype (see Ryo::Builder.build)
13
+ #
14
+ # @return [Ryo::BasicObject]
15
+ # Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
16
+ def self.create(props, prototype = nil)
17
+ ::Ryo::Builder.build(self, props, prototype)
18
+ end
19
+
20
+ ##
21
+ # Creates a Ryo object by recursively walking a Hash object.
22
+ #
23
+ # @param props (see Ryo::Builder.recursive_build)
24
+ # @param prototype (see Ryo::Builder.recursive_build)
25
+ #
26
+ # @return [Ryo::BasicObject]
27
+ # Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
28
+ def self.from(props, prototype = nil)
29
+ ::Ryo::Builder.recursive_build(self, props, prototype)
30
+ end
31
+
32
+ ##
33
+ # Duplicates the internals of a Ryo object.
34
+ #
35
+ # @param [Ryo::BasicObject] ryo
36
+ # A Ryo object.
37
+ #
38
+ # @return [Ryo::BasicObject]
39
+ # Returns a Ryo object.
40
+ def initialize_dup(ryo)
41
+ ::Ryo.set_table_of(self, ::Ryo.table_of(ryo).dup)
42
+ ::Ryo.extend!(self, ::Ryo)
43
+ end
44
+ end
45
+
46
+ ##
47
+ # @example
48
+ # point = Ryo::BasicObject(x: 0, y: 0)
49
+ # p [point.x, point.y] # => [0, 0]
50
+ #
51
+ # @param props (see Ryo::Builder.build)
52
+ # @param prototype (see Ryo::Builder.build)
53
+ #
54
+ # @return [Ryo::BasicObject]
55
+ # Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
56
+ def Ryo.BasicObject(props, prototype = nil)
57
+ Ryo::BasicObject.create(props, prototype)
58
+ end