ryo.rb 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/specs.yml +23 -0
- data/.gitignore +6 -0
- data/.gitlab-ci.yml +9 -0
- data/.rubocop.yml +56 -0
- data/.yardoc-template/default/fulldoc/html/css/0x1eef.css +15 -0
- data/.yardoc-template/default/layout/html/setup.rb +5 -0
- data/.yardoc-template/default/module/setup.rb +7 -0
- data/.yardopts +4 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +373 -0
- data/Rakefile +3 -0
- data/lib/ryo/basic_object.rb +58 -0
- data/lib/ryo/builder.rb +106 -0
- data/lib/ryo/enumerable.rb +214 -0
- data/lib/ryo/function.rb +68 -0
- data/lib/ryo/keywords.rb +67 -0
- data/lib/ryo/lazy.rb +4 -0
- data/lib/ryo/object.rb +58 -0
- data/lib/ryo/reflect.rb +379 -0
- data/lib/ryo/version.rb +5 -0
- data/lib/ryo.rb +197 -0
- data/ryo.rb.gemspec +21 -0
- data/share/ryo.rb/examples/1.0_prototypes_point_object.rb +12 -0
- data/share/ryo.rb/examples/1.1_prototypes_ryo_fn.rb +14 -0
- data/share/ryo.rb/examples/2.0_iteration_each.rb +13 -0
- data/share/ryo.rb/examples/2.1_iteration_map.rb +16 -0
- data/share/ryo.rb/examples/2.2_iteration_ancestors.rb +13 -0
- data/share/ryo.rb/examples/3.0_recursion_ryo_from.rb +13 -0
- data/share/ryo.rb/examples/3.1_recursion_ryo_from_with_array.rb +19 -0
- data/share/ryo.rb/examples/3.2_recursion_ryo_from_with_openstruct.rb +14 -0
- data/share/ryo.rb/examples/4.0_basicobject_ryo_basicobject.rb +12 -0
- data/share/ryo.rb/examples/4.1_basicobject_ryo_basicobject_from.rb +13 -0
- data/share/ryo.rb/examples/5_collisions_resolution_strategy.rb +8 -0
- data/share/ryo.rb/examples/6_beyond_hash_objects.rb +20 -0
- data/share/ryo.rb/examples/7_ryo_lazy.rb +14 -0
- data/share/ryo.rb/examples/setup.rb +3 -0
- data/spec/readme_spec.rb +79 -0
- data/spec/ryo_basic_object_spec.rb +60 -0
- data/spec/ryo_enumerable_spec.rb +197 -0
- data/spec/ryo_keywords_spec.rb +86 -0
- data/spec/ryo_object_spec.rb +71 -0
- data/spec/ryo_prototypes_spec.rb +45 -0
- data/spec/ryo_reflect_spec.rb +175 -0
- data/spec/ryo_spec.rb +130 -0
- data/spec/setup.rb +5 -0
- metadata +173 -0
data/lib/ryo/builder.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# {Ryo::Builder Ryo::Builder} is a module that's used underneath Ryo's public
|
5
|
+
# interface when creating instances of {Ryo::Object Ryo::Object}, and
|
6
|
+
# {Ryo::BasicObject Ryo::BasicObject}. This module is not intended to be
|
7
|
+
# used directly.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module Ryo::Builder
|
11
|
+
##
|
12
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] buildee
|
13
|
+
# The class of the object to build.
|
14
|
+
#
|
15
|
+
# @param [<Hash, Ryo::Object, Ryo::BasicObject, #each_pair>] props
|
16
|
+
# A Hash object, an object that implements "#each_pair", or a Ryo object.
|
17
|
+
#
|
18
|
+
# @param [<Ryo::Object, Ryo::BasicObject>, nil] prototype
|
19
|
+
# The prototype, or nil for none.
|
20
|
+
#
|
21
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
22
|
+
# Returns a Ryo object.
|
23
|
+
#
|
24
|
+
# @note
|
25
|
+
# When "props" is given as a Ryo object, a duplicate Ryo object is
|
26
|
+
# returned in its place.
|
27
|
+
def self.build(buildee, props, prototype = nil)
|
28
|
+
if Ryo.ryo?(props)
|
29
|
+
build(builedee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
30
|
+
else
|
31
|
+
ryo = buildee.new
|
32
|
+
Ryo.set_prototype_of(ryo, prototype)
|
33
|
+
Ryo.set_table_of(ryo, {})
|
34
|
+
Ryo.extend!(ryo, Ryo)
|
35
|
+
props.each_pair { ryo[_1] = _2 }
|
36
|
+
ryo
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Creates a Ryo object by recursively walking a Hash object, or an Array of Hash objects.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# objects = Ryo.from([{x: 0, y: 0}, "foo", {point: {x: 0, y: 0}}])
|
45
|
+
# objects[0].x # => 0
|
46
|
+
# objects[1] # => "foo"
|
47
|
+
# objects[2].point.x # => 0
|
48
|
+
#
|
49
|
+
# @param buildee (see Ryo::Builder.build)
|
50
|
+
#
|
51
|
+
# @param [<Hash, Ryo::Object, Ryo::BasicObject, Array, #each_pair, #each> ] props
|
52
|
+
# A Hash object, a Ryo object, or an array composed of either Hash / Ryo objects.
|
53
|
+
#
|
54
|
+
# @param prototype (see Ryo::Builder.build)
|
55
|
+
#
|
56
|
+
# @return (see Ryo::Builder.build)
|
57
|
+
#
|
58
|
+
# @note
|
59
|
+
# When "props" is given as a Ryo object, a duplicate Ryo object is
|
60
|
+
# returned in its place.
|
61
|
+
def self.recursive_build(buildee, props, prototype = nil)
|
62
|
+
if Ryo.ryo?(props)
|
63
|
+
recursive_build(buildee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
64
|
+
elsif eachless?(props)
|
65
|
+
raise TypeError, "The provided object does not implement #each / #each_pair"
|
66
|
+
elsif !props.respond_to?(:each_pair)
|
67
|
+
map(props) do
|
68
|
+
noop = Ryo.ryo?(_1) || !_1.respond_to?(:each_pair)
|
69
|
+
noop ? _1 : recursive_build(buildee, _1)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
visited = {}
|
73
|
+
props.each_pair { visited[_1] = map_value(buildee, _2) }
|
74
|
+
build(buildee, visited, prototype)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# @private
|
80
|
+
def self.map_value(buildee, value)
|
81
|
+
if Ryo.ryo?(value) || eachless?(value)
|
82
|
+
value
|
83
|
+
elsif value.respond_to?(:each_pair)
|
84
|
+
recursive_build(buildee, value)
|
85
|
+
elsif value.respond_to?(:each)
|
86
|
+
map(value) { map_value(buildee, _1) }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
private_class_method :map_value
|
90
|
+
|
91
|
+
##
|
92
|
+
# @private
|
93
|
+
def self.eachless?(value)
|
94
|
+
!value.respond_to?(:each) && !value.respond_to?(:each_pair)
|
95
|
+
end
|
96
|
+
private_class_method :eachless?
|
97
|
+
|
98
|
+
##
|
99
|
+
# @private
|
100
|
+
def self.map(obj)
|
101
|
+
ary = []
|
102
|
+
obj.each { ary.push(yield(_1)) }
|
103
|
+
ary
|
104
|
+
end
|
105
|
+
private_class_method :map
|
106
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Enumerable Ryo::Enumerable} module implements methods
|
5
|
+
# for iterating through and performing operations on Ryo objects.
|
6
|
+
# The methods implemented by this module are available as singleton
|
7
|
+
# methods on the {Ryo} module.
|
8
|
+
module Ryo::Enumerable
|
9
|
+
##
|
10
|
+
# The {#each} methods iterates a Ryo object, and yields a key / value pair.
|
11
|
+
# When a block is not given, {#each} returns an Enumerator.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# point_a = Ryo(x: 1, y: 2)
|
15
|
+
# point_b = Ryo(y: 1)
|
16
|
+
# Ryo.each(point_b) { p [_1, _2] }
|
17
|
+
# # ["y", 1]
|
18
|
+
# # ["y", 2]
|
19
|
+
# # ["x", 1]
|
20
|
+
#
|
21
|
+
# @param [Ryo::Object, Ryo::BasicObject] ryo
|
22
|
+
# A Ryo object.
|
23
|
+
#
|
24
|
+
# @param ancestors (see #each_ryo)
|
25
|
+
#
|
26
|
+
# @return [<Enumerator, Array>]
|
27
|
+
# Returns an Enumerator when a block is not given, otherwise returns an Array.
|
28
|
+
def each(ryo, ancestors: nil)
|
29
|
+
return enum_for(:each, ryo) unless block_given?
|
30
|
+
each_ryo(ryo, ancestors: ancestors) do |_, key, value|
|
31
|
+
yield(key, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# The {#each_ryo} method iterates through a Ryo object, and its prototypes.
|
37
|
+
# {#each_ryo} yields three parameters: a Ryo object, a key, and a value.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# point_a = Ryo(x: 1, y: 2)
|
41
|
+
# point_b = Ryo({y: 3}, point_a)
|
42
|
+
# Ryo.each_ryo(point_b) { |ryo, key, value| p [ryo, key, value] }
|
43
|
+
# # [point_b, "y", 3]
|
44
|
+
# # [point_a, "x", 1]
|
45
|
+
# # [point_a, "y", 2]
|
46
|
+
#
|
47
|
+
# @param [<Ryo::BasicObject, Ryo::Object>] ryo
|
48
|
+
# A Ryo object.
|
49
|
+
#
|
50
|
+
# @param [Integer] ancestors
|
51
|
+
# `ancestors` is an integer that determines how far up the prototype chain a
|
52
|
+
# {Ryo::Enumerable Ryo::Enumerable} method can go. 0 covers a Ryo object,
|
53
|
+
# and none of the prototypes in its prototype chain. 1 covers a Ryo object,
|
54
|
+
# and one of the prototypes in its prototype chain - and so on. The default
|
55
|
+
# behavior is to traverse the entire prototype chain.
|
56
|
+
#
|
57
|
+
# @return [<Ryo::BasicObject, Ryo::Object>]
|
58
|
+
def each_ryo(ryo, ancestors: nil)
|
59
|
+
proto_chain = [ryo, *prototype_chain_of(ryo)]
|
60
|
+
ancestors ||= -1
|
61
|
+
proto_chain[0..ancestors].each do |ryo|
|
62
|
+
properties_of(ryo).each do |key|
|
63
|
+
yield(ryo, key, ryo[key])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
ryo
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# The {#map} method creates a copy of a Ryo object, and then performs a map operation
|
71
|
+
# on the copy and its prototypes.
|
72
|
+
#
|
73
|
+
# @param (see #map!)
|
74
|
+
# @return (see #map!)
|
75
|
+
def map(ryo, ancestors: nil, &b)
|
76
|
+
map!(Ryo.dup(ryo), ancestors: ancestors, &b)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# The {#map!} method performs an in-place map operation on a Ryo object, and its prototypes.
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# point = Ryo(x: 2, y: 4)
|
84
|
+
# Ryo.map!(point) { _2 * 2 }
|
85
|
+
# [point.x, point.y]
|
86
|
+
# # => [4, 8]
|
87
|
+
#
|
88
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
89
|
+
# A Ryo object.
|
90
|
+
#
|
91
|
+
# @param ancestors (see #each_ryo)
|
92
|
+
#
|
93
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
94
|
+
def map!(ryo, ancestors: nil)
|
95
|
+
each_ryo(ryo, ancestors: ancestors) do |ryo, key, value|
|
96
|
+
ryo[key] = yield(key, value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# The {#select} method creates a copy of a Ryo object, and then performs a filter operation
|
102
|
+
# on the copy and its prototypes.
|
103
|
+
#
|
104
|
+
# @param (see #select!)
|
105
|
+
# @return (see #select!)
|
106
|
+
def select(ryo, ancestors: nil, &b)
|
107
|
+
select!(Ryo.dup(ryo), ancestors: ancestors, &b)
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# The {#select!} method performs an in-place filter operation on a Ryo object, and
|
112
|
+
# its prototypes.
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
116
|
+
# point_b = Ryo({z: 4}, point_a)
|
117
|
+
# Ryo.select!(point_b) { |key, value| %w(x y).include?(key) }
|
118
|
+
# [point_b.x, point_b.y, point_b.z]
|
119
|
+
# # => [1, 2, nil]
|
120
|
+
#
|
121
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
122
|
+
# A Ryo object.
|
123
|
+
#
|
124
|
+
# @param ancestors (see #each_ryo)
|
125
|
+
#
|
126
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
127
|
+
def select!(ryo, ancestors: nil)
|
128
|
+
each_ryo(ryo, ancestors: ancestors) do |ryo, key, value|
|
129
|
+
delete(ryo, key) unless yield(key, value)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# The {#reject} method creates a copy of a Ryo object, and then performs a filter operation
|
135
|
+
# on the copy and its prototypes.
|
136
|
+
#
|
137
|
+
# @param (see #reject!)
|
138
|
+
# @return (see #reject!)
|
139
|
+
def reject(ryo, ancestors: nil, &b)
|
140
|
+
reject!(Ryo.dup(ryo), ancestors: ancestors, &b)
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# The {#reject!} method performs an in-place filter operation on a Ryo object, and
|
145
|
+
# its prototypes.
|
146
|
+
#
|
147
|
+
# @example
|
148
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
149
|
+
# point_b = Ryo({z: 4}, point_a)
|
150
|
+
# Ryo.reject!(point_b) { |key, value| value > 2 }
|
151
|
+
# [point_b.x, point_b.y, point_b.z]
|
152
|
+
# # => [1, 2, nil]
|
153
|
+
#
|
154
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
155
|
+
# A Ryo object.
|
156
|
+
#
|
157
|
+
# @param ancestors (see #each_ryo)
|
158
|
+
#
|
159
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
160
|
+
def reject!(ryo, ancestors: nil)
|
161
|
+
each_ryo(ryo, ancestors: ancestors) do |ryo, key, value|
|
162
|
+
delete(ryo, key) if yield(key, value)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# The {#any?} method iterates through a Ryo object, and its prototypes - yielding a
|
168
|
+
# key / value pair to a block. If the block ever returns a truthy value, {#any?} will
|
169
|
+
# break from the iteration and return true - otherwise false will be returned.
|
170
|
+
#
|
171
|
+
# @param ancestors (see #each_ryo)
|
172
|
+
# @return [Boolean]
|
173
|
+
def any?(ryo, ancestors: nil)
|
174
|
+
each_ryo(ryo, ancestors: ancestors) do |_, key, value|
|
175
|
+
return true if yield(key, value)
|
176
|
+
end
|
177
|
+
false
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# The {#all?} method iterates through a Ryo object, and its prototypes - yielding a
|
182
|
+
# key / value pair to a block. If the block ever returns a falsey value, {#all?} will
|
183
|
+
# break from the iteration and return false - otherwise true will be returned.
|
184
|
+
#
|
185
|
+
# @param ancestors (see #each_ryo)
|
186
|
+
# @return [Boolean]
|
187
|
+
def all?(ryo, ancestors: nil)
|
188
|
+
each_ryo(ryo, ancestors: ancestors) do |_, key, value|
|
189
|
+
return false unless yield(key, value)
|
190
|
+
end
|
191
|
+
true
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# The {#find} method iterates through a Ryo object, and its prototypes - yielding a
|
196
|
+
# key / value pair to a block. If the block ever returns a truthy value, {#find} will
|
197
|
+
# break from the iteration and return a Ryo object - otherwise nil will be returned.
|
198
|
+
#
|
199
|
+
# @example
|
200
|
+
# point_a = Ryo(x: 5)
|
201
|
+
# point_b = Ryo({y: 10}, point_a)
|
202
|
+
# point_c = Ryo({z: 15}, point_b)
|
203
|
+
# ryo = Ryo.find(point_c) { |key, value| value == 5 }
|
204
|
+
# ryo == point_a # => true
|
205
|
+
#
|
206
|
+
# @param ancestors (see #each_ryo)
|
207
|
+
# @return [<Ryo::Object, Ryo::BasicObject>, nil]
|
208
|
+
def find(ryo, ancestors: nil)
|
209
|
+
each_ryo(ryo, ancestors: ancestors) do |ryo, key, value|
|
210
|
+
return ryo if yield(key, value)
|
211
|
+
end
|
212
|
+
nil
|
213
|
+
end
|
214
|
+
end
|
data/lib/ryo/function.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Function Ryo::Function} class represents a Ryo
|
5
|
+
# function. The class is usually not used directly but through
|
6
|
+
# {Ryo::Keywords#fn Ryo.fn}. A Ryo function has a special relationship
|
7
|
+
# with Ryo objects: when a Ryo function is assigned as a property
|
8
|
+
# on a Ryo object - the "self" of the function becomes bound to the
|
9
|
+
# Ryo object.
|
10
|
+
class Ryo::Function
|
11
|
+
##
|
12
|
+
# @param [Proc] body
|
13
|
+
# The body of the function as a block.
|
14
|
+
#
|
15
|
+
# @return [Ryo::Function]
|
16
|
+
# Returns an instance of {Ryo::Function Ryo::Function}.
|
17
|
+
def initialize(&body)
|
18
|
+
@body = body
|
19
|
+
@ryo = nil
|
20
|
+
@to_proc = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
25
|
+
# Returns the object that the function's "self" is bound to.
|
26
|
+
def receiver
|
27
|
+
@ryo
|
28
|
+
end
|
29
|
+
alias_method :self, :receiver
|
30
|
+
|
31
|
+
##
|
32
|
+
# Change the receiver (self) of the function.
|
33
|
+
#
|
34
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
35
|
+
# A Ryo object.
|
36
|
+
#
|
37
|
+
# @return [nil]
|
38
|
+
def bind!(ryo)
|
39
|
+
@ryo = ryo
|
40
|
+
@to_proc = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Call the function.
|
45
|
+
def call(...)
|
46
|
+
to_proc.call(...)
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @return [Proc]
|
51
|
+
# Returns the function as a lambda bound to {#receiver}.
|
52
|
+
def to_proc
|
53
|
+
@to_proc ||= lambda!(@body)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def lambda!(body)
|
59
|
+
ryo, lambda = @ryo, nil
|
60
|
+
Module.new do
|
61
|
+
define_method(:__function__, &body)
|
62
|
+
lambda = instance_method(:__function__)
|
63
|
+
.bind(ryo)
|
64
|
+
.to_proc
|
65
|
+
end
|
66
|
+
lambda
|
67
|
+
end
|
68
|
+
end
|
data/lib/ryo/keywords.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Keywords Ryo::Keywords} module implements Ryo equivalents
|
5
|
+
# to some of JavaScript's keywords - for example: the **in** and **delete**
|
6
|
+
# operators. The instance methods of this module are available as singleton
|
7
|
+
# methods on the {Ryo} module.
|
8
|
+
module Ryo::Keywords
|
9
|
+
##
|
10
|
+
# @example
|
11
|
+
# point = Ryo(x: 0, y: 0, print: Ryo.fn { print x, y, "\n" })
|
12
|
+
# point.print.()
|
13
|
+
#
|
14
|
+
# @param [Proc] b
|
15
|
+
# The function's body.
|
16
|
+
#
|
17
|
+
# @return [Ryo::Function]
|
18
|
+
# Returns a Ryo function.
|
19
|
+
#
|
20
|
+
# @see Ryo::Function Ryo::Function
|
21
|
+
def fn(&b)
|
22
|
+
Ryo::Function.new(&b)
|
23
|
+
end
|
24
|
+
alias_method :function, :fn
|
25
|
+
|
26
|
+
##
|
27
|
+
# Equivalent to JavaScript's **in** operator.
|
28
|
+
#
|
29
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
30
|
+
# A Ryo object.
|
31
|
+
#
|
32
|
+
# @param [<String, #to_s>] property
|
33
|
+
# A property name.
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
# Returns true when **property** is a member of **ryo**, or its prototype chain.
|
37
|
+
def in?(ryo, property)
|
38
|
+
return false unless ryo
|
39
|
+
property?(ryo, property) || in?(prototype_of(ryo), property)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# The {#delete} method deletes a property from a Ryo object.
|
44
|
+
# More or less equivalent to JavaScript's "delete" operator.
|
45
|
+
#
|
46
|
+
# @note
|
47
|
+
# This method does not delete properties from the prototype(s)
|
48
|
+
# of a Ryo object. <br>
|
49
|
+
# For that - see {Ryo::Reflect#delete! Ryo::Reflect#delete!}.
|
50
|
+
#
|
51
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
52
|
+
# A Ryo object.
|
53
|
+
#
|
54
|
+
# @param [<String, #to_s>] property
|
55
|
+
# A property name.
|
56
|
+
#
|
57
|
+
# @return [void]
|
58
|
+
def delete(ryo, property)
|
59
|
+
property = property.to_s
|
60
|
+
if property?(ryo, property)
|
61
|
+
table_of(ryo).delete(property)
|
62
|
+
else
|
63
|
+
return if getter_defined?(ryo, property)
|
64
|
+
define_method!(ryo, property) { ryo[property] }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/ryo/lazy.rb
ADDED
data/lib/ryo/object.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# {Ryo::Object Ryo::Object} is a Ryo object and subclass of
|
5
|
+
# Ruby's Object class that can be created by using
|
6
|
+
# [Ryo()](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method),
|
7
|
+
# {Ryo.Object Ryo.Object()}, {Ryo::Object.from Ryo::Object.from},
|
8
|
+
# or {Ryo::Object.create Ryo::Object.create}.
|
9
|
+
class Ryo::Object
|
10
|
+
##
|
11
|
+
# @param props (see Ryo::Builder.build)
|
12
|
+
# @param prototype (see Ryo::Builder.build)
|
13
|
+
#
|
14
|
+
# @return [Ryo::Object]
|
15
|
+
# Returns an instance of {Ryo::Object Ryo::Object}.
|
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::Object]
|
27
|
+
# Returns an instance of {Ryo::Object Ryo::Object}.
|
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::Object] ryo
|
36
|
+
# A Ryo object.
|
37
|
+
#
|
38
|
+
# @return [Ryo::Object]
|
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::Object(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::Object]
|
55
|
+
# Returns an instance of {Ryo::Object Ryo::Object}.
|
56
|
+
def Ryo.Object(props, prototype = nil)
|
57
|
+
Ryo::Object.create(props, prototype)
|
58
|
+
end
|