quran-audio 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bundle/io-line.rb/lib/io/line/multiple.rb +19 -0
- data/bundle/io-line.rb/lib/io/line.rb +28 -0
- data/bundle/ryo.rb/lib/ryo/basic_object.rb +54 -0
- data/bundle/ryo.rb/lib/ryo/builder.rb +87 -0
- data/bundle/ryo.rb/lib/ryo/enumerable.rb +197 -0
- data/bundle/ryo.rb/lib/ryo/function.rb +68 -0
- data/bundle/ryo.rb/lib/ryo/json.rb +45 -0
- data/bundle/ryo.rb/lib/ryo/keywords.rb +55 -0
- data/bundle/ryo.rb/lib/ryo/memo.rb +4 -0
- data/bundle/ryo.rb/lib/ryo/object.rb +54 -0
- data/bundle/ryo.rb/lib/ryo/reflect.rb +264 -0
- data/bundle/ryo.rb/lib/ryo/utils.rb +68 -0
- data/bundle/ryo.rb/lib/ryo/version.rb +5 -0
- data/bundle/ryo.rb/lib/ryo/yaml.rb +45 -0
- data/bundle/ryo.rb/lib/ryo.rb +195 -0
- data/share/quran-audio/VERSION +1 -1
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f31510aaf2b2ac45001870411b82eb1e1ff7c8103cdbebb4f9b92268906b4cfb
|
4
|
+
data.tar.gz: 6c54cbdf7ed5493fcb9cc0cf0e84305adae279c2433d5f1e6204ac9ba9af9b38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2a714b375cab47aea59c2f03132e291b4f8b617a271e75aeb15b7ee9c07b0835734a35ca3ef99d988604531d4c91a68fdad0aecbebaa184c857a0c0ff123d3a
|
7
|
+
data.tar.gz: a25e352aa4d91b529e9943e07d4a58ed49f4a9c6f40ad56249f60c9a3bc038b929fef304dba2f9da0357bc8a01b7aab7abc32f18498f9150e0fa5c101311e6c8
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class IO::Line::Multiple
|
4
|
+
def initialize(lines, cursor)
|
5
|
+
@lines = lines
|
6
|
+
@cursor = cursor
|
7
|
+
end
|
8
|
+
|
9
|
+
def print(*strs, lineno:)
|
10
|
+
line = @lines[lineno]
|
11
|
+
if lineno > @cursor
|
12
|
+
line.io.cursor_down(lineno - @cursor)
|
13
|
+
elsif lineno < @cursor
|
14
|
+
line.io.cursor_up(lineno + @cursor)
|
15
|
+
end
|
16
|
+
@cursor = lineno
|
17
|
+
line.rewind.print(*strs)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class IO::Line
|
4
|
+
require "io/console"
|
5
|
+
require_relative "line/multiple"
|
6
|
+
|
7
|
+
VERSION = "0.1.0"
|
8
|
+
attr_reader :io
|
9
|
+
|
10
|
+
def initialize(io)
|
11
|
+
@io = io
|
12
|
+
end
|
13
|
+
|
14
|
+
def print(*strs)
|
15
|
+
tap { @io.print(strs.join.gsub($/, "")) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def end
|
19
|
+
tap { @io.print($/) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def rewind
|
23
|
+
tap do
|
24
|
+
@io.erase_line(2)
|
25
|
+
@io.goto_column(0)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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
|
+
# @return [Ryo::BasicObject]
|
14
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
15
|
+
def self.create(props, prototype = nil)
|
16
|
+
::Ryo::Builder.build(self, props, prototype)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Creates a Ryo object by recursively walking a Hash object
|
21
|
+
#
|
22
|
+
# @param props (see Ryo::Builder.recursive_build)
|
23
|
+
# @param prototype (see Ryo::Builder.recursive_build)
|
24
|
+
# @return [Ryo::BasicObject]
|
25
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
26
|
+
def self.from(props, prototype = nil)
|
27
|
+
::Ryo::Builder.recursive_build(self, props, prototype)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Duplicates the internals of a Ryo object
|
32
|
+
#
|
33
|
+
# @param [Ryo::BasicObject] ryo
|
34
|
+
# A Ryo object
|
35
|
+
# @return [Ryo::BasicObject]
|
36
|
+
# Returns a Ryo object
|
37
|
+
def initialize_dup(ryo)
|
38
|
+
::Ryo.set_table_of(self, ::Ryo.table_of(ryo).dup)
|
39
|
+
::Ryo.extend!(self, ::Ryo)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# @example
|
45
|
+
# point = Ryo::BasicObject(x: 0, y: 0)
|
46
|
+
# p [point.x, point.y] # => [0, 0]
|
47
|
+
#
|
48
|
+
# @param props (see Ryo::Builder.build)
|
49
|
+
# @param prototype (see Ryo::Builder.build)
|
50
|
+
# @return [Ryo::BasicObject]
|
51
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
52
|
+
def Ryo.BasicObject(props, prototype = nil)
|
53
|
+
Ryo::BasicObject.create(props, prototype)
|
54
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Builder Ryo::Builder} module is responsible for
|
5
|
+
# the creation of instances of {Ryo::Object Ryo::Object},
|
6
|
+
# and {Ryo::BasicObject Ryo::BasicObject}. This module is
|
7
|
+
# not intended to be used directly.
|
8
|
+
# @api private
|
9
|
+
module Ryo::Builder
|
10
|
+
##
|
11
|
+
# @note
|
12
|
+
# When "props" is given as a Ryo object, a duplicate Ryo object is
|
13
|
+
# returned in its place
|
14
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] buildee
|
15
|
+
# @param [<#each_pair>] props
|
16
|
+
# @param [<Ryo::Object, Ryo::BasicObject>, nil] prototype
|
17
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
18
|
+
# Returns a Ryo object
|
19
|
+
def self.build(buildee, props, prototype = nil)
|
20
|
+
if Ryo.ryo?(props)
|
21
|
+
build(buildee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
22
|
+
else
|
23
|
+
ryo = buildee.new
|
24
|
+
Ryo.set_prototype_of(ryo, prototype)
|
25
|
+
Ryo.set_table_of(ryo, {})
|
26
|
+
Ryo.extend!(ryo, Ryo)
|
27
|
+
props.each_pair { ryo[_1] = _2 }
|
28
|
+
ryo
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Creates a Ryo object by recursively walking a Hash object, or
|
34
|
+
# an Array of Hash objects
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# objects = Ryo.from([{x: 0, y: 0}, "foo", {point: {x: 0, y: 0}}])
|
38
|
+
# objects[0].x # => 0
|
39
|
+
# objects[1] # => "foo"
|
40
|
+
# objects[2].point.x # => 0
|
41
|
+
#
|
42
|
+
# @note (see Ryo::Builder.build)
|
43
|
+
# @param (see Ryo::Builder.build)
|
44
|
+
# @return (see Ryo::Builder.build)
|
45
|
+
def self.recursive_build(buildee, props, prototype = nil)
|
46
|
+
if Ryo.ryo?(props)
|
47
|
+
recursive_build(buildee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
48
|
+
elsif !respond_to_each?(props)
|
49
|
+
raise TypeError, "The provided object does not implement #each / #each_pair"
|
50
|
+
elsif !props.respond_to?(:each_pair)
|
51
|
+
map(props) do
|
52
|
+
noop = Ryo.ryo?(_1) || !_1.respond_to?(:each_pair)
|
53
|
+
noop ? _1 : recursive_build(buildee, _1)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
visited = {}
|
57
|
+
props.each_pair { visited[_1] = map_value(buildee, _2) }
|
58
|
+
build(buildee, visited, prototype)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Private
|
63
|
+
private
|
64
|
+
|
65
|
+
def map_value(buildee, value)
|
66
|
+
if Ryo.ryo?(value) || !respond_to_each?(value)
|
67
|
+
value
|
68
|
+
elsif value.respond_to?(:each_pair)
|
69
|
+
recursive_build(buildee, value)
|
70
|
+
elsif value.respond_to?(:each)
|
71
|
+
map(value) { map_value(buildee, _1) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def respond_to_each?(value)
|
76
|
+
value.respond_to?(:each) || value.respond_to?(:each_pair)
|
77
|
+
end
|
78
|
+
|
79
|
+
def map(obj)
|
80
|
+
ary = []
|
81
|
+
obj.each { ary.push(yield(_1)) }
|
82
|
+
ary
|
83
|
+
end
|
84
|
+
end
|
85
|
+
private_constant :Private
|
86
|
+
extend Private
|
87
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Enumerable Ryo::Enumerable} module provides methods
|
5
|
+
# that are similar to Ruby's Enumerable module, and at the same
|
6
|
+
# time - intentionally different.
|
7
|
+
#
|
8
|
+
# For example: {Ryo::Enumerable Ryo::Enumerable}
|
9
|
+
# methods receive 'self' as an argument rather than from the
|
10
|
+
# surrounding context. The methods implemented by this
|
11
|
+
# module are available as singleton methods on the {Ryo Ryo}
|
12
|
+
# module.
|
13
|
+
module Ryo::Enumerable
|
14
|
+
##
|
15
|
+
# The {#each} method iterates through a Ryo object, and
|
16
|
+
# yields two parameters: a key, and a value
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# point_a = Ryo(x: 1, y: 2)
|
20
|
+
# point_b = Ryo(y: 1)
|
21
|
+
# Ryo.each(point_b) { p [_1, _2] }
|
22
|
+
# # ["y", 1]
|
23
|
+
# # ["y", 2]
|
24
|
+
# # ["x", 1]
|
25
|
+
#
|
26
|
+
# @param (see #each_ryo)
|
27
|
+
# @return [<Enumerator, Array>]
|
28
|
+
def each(ryo, ancestors: nil)
|
29
|
+
return enum_for(:each, ryo) unless block_given?
|
30
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
31
|
+
yield(key, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# The {#each_ryo} method iterates through a Ryo object,
|
37
|
+
# and its prototypes. {#each_ryo} yields three parameters:
|
38
|
+
# a Ryo object, a key, and a value
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# point_a = Ryo(x: 1, y: 2)
|
42
|
+
# point_b = Ryo({y: 3}, point_a)
|
43
|
+
# Ryo.each_ryo(point_b) { |ryo, key, value| p [ryo, key, value] }
|
44
|
+
# # [point_b, "y", 3]
|
45
|
+
# # [point_a, "x", 1]
|
46
|
+
# # [point_a, "y", 2]
|
47
|
+
#
|
48
|
+
# @param [<Ryo::BasicObject, Ryo::Object>] ryo
|
49
|
+
# @param [Integer] ancestors
|
50
|
+
# "ancestors" is an integer that defines the traversal depth
|
51
|
+
# of a {Ryo::Enumerable Ryo::Enumerable} method. 0 covers a
|
52
|
+
# Ryo object, and none of the prototypes in its prototype
|
53
|
+
# chain. 1 covers a Ryo object, and one of the prototypes
|
54
|
+
# in its prototype chain - and so on. The default covers
|
55
|
+
# the entire prototype chain.
|
56
|
+
# @return [<Ryo::BasicObject, Ryo::Object>]
|
57
|
+
def each_ryo(ryo, ancestors: nil)
|
58
|
+
proto_chain = [ryo, *prototype_chain_of(ryo)]
|
59
|
+
ancestors ||= -1
|
60
|
+
proto_chain[0..ancestors].each do |ryo|
|
61
|
+
properties_of(ryo).each do |key|
|
62
|
+
yield(ryo, key, ryo[key])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
ryo
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# The {#map} method creates a copy of a Ryo object,
|
70
|
+
# and then performs a map operation on the copy and
|
71
|
+
# its prototypes
|
72
|
+
#
|
73
|
+
# @param (see #each_ryo)
|
74
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
75
|
+
def map(ryo, ancestors: nil, &b)
|
76
|
+
map!(Ryo.dup(ryo), ancestors:, &b)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# The {#map!} method performs an in-place map operation
|
81
|
+
# on a Ryo object, and its prototypes
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# point = Ryo(x: 2, y: 4)
|
85
|
+
# Ryo.map!(point) { _2 * 2 }
|
86
|
+
# [point.x, point.y]
|
87
|
+
# # => [4, 8]
|
88
|
+
#
|
89
|
+
# @param (see #each_ryo)
|
90
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
91
|
+
def map!(ryo, ancestors: nil)
|
92
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
93
|
+
ryo[key] = yield(key, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# The {#select} method creates a copy of a Ryo object, and
|
99
|
+
# then performs a filter operation on the copy and its
|
100
|
+
# prototypes
|
101
|
+
#
|
102
|
+
# @param (see #each_ryo)
|
103
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
104
|
+
def select(ryo, ancestors: nil, &b)
|
105
|
+
select!(Ryo.dup(ryo), ancestors:, &b)
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# The {#select!} method performs an in-place filter operation
|
110
|
+
# on a Ryo object, and its prototypes
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
114
|
+
# point_b = Ryo({z: 4}, point_a)
|
115
|
+
# Ryo.select!(point_b) { |key, value| %w(x y).include?(key) }
|
116
|
+
# [point_b.x, point_b.y, point_b.z]
|
117
|
+
# # => [1, 2, nil]
|
118
|
+
#
|
119
|
+
# @param (see #each_ryo)
|
120
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
121
|
+
def select!(ryo, ancestors: nil)
|
122
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
123
|
+
delete(ryo, key) unless yield(key, value)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# The {#reject} method creates a copy of a Ryo object, and then
|
129
|
+
# performs a filter operation on the copy and its prototypes
|
130
|
+
#
|
131
|
+
# @param (see #each_ryo)
|
132
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
133
|
+
def reject(ryo, ancestors: nil, &b)
|
134
|
+
reject!(Ryo.dup(ryo), ancestors:, &b)
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# The {#reject!} method performs an in-place filter operation
|
139
|
+
# on a Ryo object, and its prototypes
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
143
|
+
# point_b = Ryo({z: 4}, point_a)
|
144
|
+
# Ryo.reject!(point_b) { |key, value| value > 2 }
|
145
|
+
# [point_b.x, point_b.y, point_b.z]
|
146
|
+
# # => [1, 2, nil]
|
147
|
+
#
|
148
|
+
# @param (see #each_ryo)
|
149
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
150
|
+
def reject!(ryo, ancestors: nil)
|
151
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
152
|
+
delete(ryo, key) if yield(key, value)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# @param (see #each_ryo)
|
158
|
+
# @return [Boolean]
|
159
|
+
# Returns true when the given block evaluates to
|
160
|
+
# a truthy value for at least one iteration
|
161
|
+
def any?(ryo, ancestors: nil)
|
162
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
163
|
+
return true if yield(key, value)
|
164
|
+
end
|
165
|
+
false
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# @param (see #each_ryo)
|
170
|
+
# @return [Boolean]
|
171
|
+
# Returns true when the given block evaluates to a
|
172
|
+
# truthy value for every iteration
|
173
|
+
def all?(ryo, ancestors: nil)
|
174
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
175
|
+
return false unless yield(key, value)
|
176
|
+
end
|
177
|
+
true
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# @example
|
182
|
+
# point_a = Ryo(x: 5)
|
183
|
+
# point_b = Ryo({y: 10}, point_a)
|
184
|
+
# point_c = Ryo({z: 15}, point_b)
|
185
|
+
# ryo = Ryo.find(point_c) { |key, value| value == 5 }
|
186
|
+
# ryo == point_a # => true
|
187
|
+
#
|
188
|
+
# @param (see #each_ryo)
|
189
|
+
# @return [<Ryo::Object, Ryo::BasicObject>, nil]
|
190
|
+
# Returns a Ryo object, or nil
|
191
|
+
def find(ryo, ancestors: nil)
|
192
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
193
|
+
return ryo if yield(key, value)
|
194
|
+
end
|
195
|
+
nil
|
196
|
+
end
|
197
|
+
end
|
@@ -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
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::JSON Ryo::JSON} module provides a number of methods
|
5
|
+
# for coercing JSON data into a Ryo object. It must be required
|
6
|
+
# separately to Ryo (ie: require "ryo/json"), and the methods of
|
7
|
+
# this module are then available on the {Ryo Ryo} module.
|
8
|
+
module Ryo::JSON
|
9
|
+
require "json"
|
10
|
+
extend self
|
11
|
+
|
12
|
+
##
|
13
|
+
# @example
|
14
|
+
# Ryo.from_json(path: "/foo/bar/baz.json")
|
15
|
+
# Ryo.from_json(string: "[]")
|
16
|
+
#
|
17
|
+
# @param [String] path
|
18
|
+
# The path to a JSON file
|
19
|
+
#
|
20
|
+
# @param [String] string
|
21
|
+
# A blob of JSON
|
22
|
+
#
|
23
|
+
# @param [Ryo] object
|
24
|
+
# {Ryo::Object Ryo::Object}, or {Ryo::BasicObject Ryo::BasicObject}
|
25
|
+
# Defaults to {Ryo::Object Ryo::Object}
|
26
|
+
#
|
27
|
+
# @raise [SystemCallError]
|
28
|
+
# Might raise a number of Errno exceptions
|
29
|
+
#
|
30
|
+
# @return [Ryo::Object, Ryo::BasicObject]
|
31
|
+
# Returns a Ryo object
|
32
|
+
def from_json(path: nil, string: nil, object: Ryo::Object)
|
33
|
+
if path && string
|
34
|
+
raise ArgumentError, "Provide a path or string but not both"
|
35
|
+
elsif path
|
36
|
+
object.from JSON.parse(File.binread(path))
|
37
|
+
elsif string
|
38
|
+
object.from JSON.parse(string)
|
39
|
+
else
|
40
|
+
raise ArgumentError, "No path or string provided"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Ryo.extend(self)
|
45
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Keywords Ryo::Keywords} module implements Ryo equivalents
|
5
|
+
# for some of JavaScript's keywords (eg: the **in** and **delete** operators).
|
6
|
+
# 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
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
29
|
+
# A Ryo object
|
30
|
+
# @param [<String, #to_s>] property
|
31
|
+
# A property name
|
32
|
+
# @return [Boolean]
|
33
|
+
# Returns true when **property** is a member of **ryo**, or its prototype chain
|
34
|
+
def in?(ryo, property)
|
35
|
+
return false unless ryo
|
36
|
+
property?(ryo, property) || in?(prototype_of(ryo), property)
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# The {#delete} method deletes a property from a Ryo object
|
41
|
+
# @see Ryo::Reflect#delete!
|
42
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
43
|
+
# A Ryo object
|
44
|
+
# @param [<String, #to_s>] property
|
45
|
+
# A property name
|
46
|
+
# @param [Integer] ancestors
|
47
|
+
# The number of prototypes to traverse.
|
48
|
+
# Defaults to the entire prototype chain.
|
49
|
+
# @return [void]
|
50
|
+
def delete(ryo, property, ancestors: nil)
|
51
|
+
each_ryo(ryo, ancestors:) do
|
52
|
+
Ryo.property?(_1, property) ? table_of(_1).delete(property) : nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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
|
+
# @return [Ryo::Object]
|
14
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
15
|
+
def self.create(props, prototype = nil)
|
16
|
+
Ryo::Builder.build(self, props, prototype)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Creates a Ryo object by recursively walking a Hash object
|
21
|
+
#
|
22
|
+
# @param props (see Ryo::Builder.recursive_build)
|
23
|
+
# @param prototype (see Ryo::Builder.recursive_build)
|
24
|
+
# @return [Ryo::Object]
|
25
|
+
# Returns an instance of {Ryo::Object Ryo::Object}.
|
26
|
+
def self.from(props, prototype = nil)
|
27
|
+
Ryo::Builder.recursive_build(self, props, prototype)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Duplicates the internals of a Ryo object
|
32
|
+
#
|
33
|
+
# @param [Ryo::Object] ryo
|
34
|
+
# A Ryo object
|
35
|
+
# @return [Ryo::Object]
|
36
|
+
# Returns a Ryo object
|
37
|
+
def initialize_dup(ryo)
|
38
|
+
Ryo.set_table_of(self, Ryo.table_of(ryo).dup)
|
39
|
+
Ryo.extend!(self, Ryo)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# @example
|
45
|
+
# point = Ryo::Object(x: 0, y: 0)
|
46
|
+
# p [point.x, point.y] # => [0, 0]
|
47
|
+
#
|
48
|
+
# @param props (see Ryo::Builder.build)
|
49
|
+
# @param prototype (see Ryo::Builder.build)
|
50
|
+
# @return [Ryo::Object]
|
51
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
52
|
+
def Ryo.Object(props, prototype = nil)
|
53
|
+
Ryo::Object.create(props, prototype)
|
54
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Reflect Ryo::Reflect} module mirrors
|
5
|
+
# JavaScript's [`Relfect` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect),
|
6
|
+
# and some of the static methods on JavaScript's
|
7
|
+
# [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
8
|
+
# as well.
|
9
|
+
#
|
10
|
+
# {Ryo::Reflect Ryo::Reflect} also implements Ryo-specific
|
11
|
+
# reflection features. The instance methods of this module
|
12
|
+
# are available as singleton methods on the {Ryo Ryo}
|
13
|
+
# module.
|
14
|
+
module Ryo::Reflect
|
15
|
+
extend self
|
16
|
+
|
17
|
+
##
|
18
|
+
# @group JavaScript equivalents (Reflect)
|
19
|
+
|
20
|
+
##
|
21
|
+
# Equivalent to JavaScript's `Reflect.getPrototypeOf`
|
22
|
+
#
|
23
|
+
# @param [Ryo] ryo
|
24
|
+
# A Ryo object.
|
25
|
+
#
|
26
|
+
# @return [Ryo, nil]
|
27
|
+
# Returns the prototype of the *ryo* object.
|
28
|
+
def prototype_of(ryo)
|
29
|
+
kernel(:instance_variable_get)
|
30
|
+
.bind_call(ryo, :@_proto)
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Equivalent to JavaScript's `Reflect.setPrototypeOf`
|
35
|
+
#
|
36
|
+
# @param [Ryo] ryo
|
37
|
+
# A Ryo object.
|
38
|
+
#
|
39
|
+
# @param [Ryo] prototype
|
40
|
+
# The prototype to assign to *ryo*.
|
41
|
+
#
|
42
|
+
# @return [nil]
|
43
|
+
def set_prototype_of(ryo, prototype)
|
44
|
+
kernel(:instance_variable_set)
|
45
|
+
.bind_call(ryo, :@_proto, prototype)
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Equivalent to JavaScript's `Reflect.defineProperty`
|
51
|
+
#
|
52
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
53
|
+
# A Ryo object
|
54
|
+
# @param [<String, #to_s>] property
|
55
|
+
# The name of a property
|
56
|
+
# @param [Object, BasicObject] value
|
57
|
+
# The property's value
|
58
|
+
# @return [void]
|
59
|
+
def define_property(ryo, property, value)
|
60
|
+
table, property = table_of(ryo), property.to_s
|
61
|
+
kernel(:tap).bind_call(value) { _1.bind!(ryo) if function?(_1) }
|
62
|
+
table[property] = value
|
63
|
+
# Define setter
|
64
|
+
if !setter_defined?(ryo, property) && property[-1] != "?"
|
65
|
+
define_method!(ryo, "#{property}=") { ryo[property] = _1 }
|
66
|
+
end
|
67
|
+
# Define getter
|
68
|
+
return if getter_defined?(ryo, property)
|
69
|
+
define_method!(ryo, property) { |*args, &b|
|
70
|
+
(args.empty? && b.nil?) ? ryo[property] :
|
71
|
+
super(*args, &b)
|
72
|
+
}
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Equivalent to JavaScript's `Reflect.ownKeys`, and
|
78
|
+
# JavaScript's `Object.keys`
|
79
|
+
#
|
80
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
81
|
+
# A Ryo object
|
82
|
+
# @return [Array<String>]
|
83
|
+
# Returns the properties defined on a Ryo object
|
84
|
+
def properties_of(ryo)
|
85
|
+
table_of(ryo).keys
|
86
|
+
end
|
87
|
+
|
88
|
+
# @endgroup
|
89
|
+
|
90
|
+
##
|
91
|
+
# @group JavaScript equivalents (Object)
|
92
|
+
|
93
|
+
##
|
94
|
+
# Equivalent to JavaScript's `Object.hasOwn`,
|
95
|
+
# and `Object.prototype.hasOwnProperty`.
|
96
|
+
#
|
97
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
98
|
+
# A Ryo object
|
99
|
+
# @param [<String, #to_s>] property
|
100
|
+
# The name of a property
|
101
|
+
# @return [Boolean]
|
102
|
+
# Returns true when the property is a member of a Ryo object
|
103
|
+
def property?(ryo, property)
|
104
|
+
table_of(ryo).key?(property.to_s)
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Equivalent to JavaScript's `Object.assign`.
|
109
|
+
#
|
110
|
+
# @param [Ryo, Hash, #to_hash] target
|
111
|
+
# The target object
|
112
|
+
# @param [Ryo, Hash, #to_hash] sources
|
113
|
+
# A variable number of source objects that
|
114
|
+
# will be merged with the target object
|
115
|
+
# @return [Ryo]
|
116
|
+
# Returns the modified target object.
|
117
|
+
def assign(target, *sources)
|
118
|
+
sources.each do |source|
|
119
|
+
to_hash(source).each { target[_1.to_s] = _2 }
|
120
|
+
end
|
121
|
+
target
|
122
|
+
end
|
123
|
+
# @endgroup
|
124
|
+
|
125
|
+
##
|
126
|
+
# @group Ryo-specific
|
127
|
+
|
128
|
+
##
|
129
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
130
|
+
# A Ryo object
|
131
|
+
# @return [Array<Ryo::Object, Ryo::BasicObject>]
|
132
|
+
# Returns the prototype chain of a Ryo object
|
133
|
+
def prototype_chain_of(ryo)
|
134
|
+
prototypes = []
|
135
|
+
loop do
|
136
|
+
ryo = prototype_of(ryo)
|
137
|
+
break unless ryo
|
138
|
+
prototypes.push(ryo)
|
139
|
+
end
|
140
|
+
prototypes
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
145
|
+
# A Ryo object
|
146
|
+
# @param [Boolean] recursive
|
147
|
+
# When true, nested Ryo objects are replaced by
|
148
|
+
# their table as well
|
149
|
+
# @return [Hash]
|
150
|
+
# Returns the table of a Ryo object
|
151
|
+
def table_of(ryo, recursive: false)
|
152
|
+
table = kernel(:instance_variable_get).bind_call(ryo, :@_table)
|
153
|
+
if recursive
|
154
|
+
table.each do |key, value|
|
155
|
+
if ryo?(value)
|
156
|
+
table[key] = table_of(value, recursive:)
|
157
|
+
elsif value.respond_to?(:each)
|
158
|
+
table[key] = value.respond_to?(:each_pair) ?
|
159
|
+
value : value.map { table_of(_1, recursive:) }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
table
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Sets the table of a Ryo object
|
168
|
+
#
|
169
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
170
|
+
# A Ryo object
|
171
|
+
# @param [Hash] table
|
172
|
+
# The table
|
173
|
+
# @return [nil]
|
174
|
+
def set_table_of(ryo, table)
|
175
|
+
kernel(:instance_variable_set)
|
176
|
+
.bind_call(ryo, :@_table, table)
|
177
|
+
nil
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
182
|
+
# A Ryo object
|
183
|
+
# @param [<String, Symbol>] method
|
184
|
+
# The name of a method
|
185
|
+
# @param [::Object, ::BasicObject] args
|
186
|
+
# Zero or more method arguments
|
187
|
+
# @param [Proc] b
|
188
|
+
# An optional block
|
189
|
+
# @return [::Object, ::BasicObject]
|
190
|
+
def call_method(ryo, method, *args, &b)
|
191
|
+
kernel(:__send__)
|
192
|
+
.bind_call(ryo, method, *args, &b)
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
197
|
+
# A Ryo object
|
198
|
+
# @return [Class]
|
199
|
+
# Returns the class of a Ryo object
|
200
|
+
def class_of(ryo)
|
201
|
+
kernel(:class).bind_call(ryo)
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# @param [Ryo::Function, Object, BasicObject] obj
|
206
|
+
# An object
|
207
|
+
# @return [Boolean]
|
208
|
+
# Returns true when given a Ryo function
|
209
|
+
def function?(obj)
|
210
|
+
Ryo::Function === obj
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# @param [Ryo::Function, Object, BasicObject] obj
|
215
|
+
# An object
|
216
|
+
# @return [Boolean]
|
217
|
+
# Returns true when given a Ryo memo
|
218
|
+
def memo?(obj)
|
219
|
+
Ryo::Memo === obj
|
220
|
+
end
|
221
|
+
alias_method :lazy?, :memo?
|
222
|
+
|
223
|
+
##
|
224
|
+
# @example
|
225
|
+
# Ryo.ryo?(Ryo::Object(x: 5, y: 12)) # => true
|
226
|
+
# Ryo.ryo?(Ryo::BasicObject(x: 10, y: 20)) # => true
|
227
|
+
# Ryo.ryo?(Object.new) # => false
|
228
|
+
#
|
229
|
+
# @param [Object, BasicObject] obj
|
230
|
+
# An object
|
231
|
+
# @return [Boolean]
|
232
|
+
# Returns true when given a Ryo object
|
233
|
+
def ryo?(obj)
|
234
|
+
Ryo === obj
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo1
|
239
|
+
# A Ryo object
|
240
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo2
|
241
|
+
# A Ryo object
|
242
|
+
# @return [Boolean]
|
243
|
+
# Returns true when the two Ryo objects are strictly equal
|
244
|
+
def equal?(ryo1, ryo2)
|
245
|
+
kernel(:equal?).bind_call(ryo1, ryo2)
|
246
|
+
end
|
247
|
+
|
248
|
+
##
|
249
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
250
|
+
# A Ryo object
|
251
|
+
# @return [String]
|
252
|
+
# Returns a String representation of a Ryo object
|
253
|
+
def inspect_object(ryo)
|
254
|
+
format(
|
255
|
+
"#<Ryo object=%{object} proto=%{proto} table=%{table}>",
|
256
|
+
object: Object.instance_method(:to_s).bind_call(ryo),
|
257
|
+
proto: prototype_of(ryo).inspect,
|
258
|
+
table: table_of(ryo).inspect
|
259
|
+
)
|
260
|
+
end
|
261
|
+
# @endgroup
|
262
|
+
|
263
|
+
include Ryo::Utils
|
264
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::Utils Ryo::Utils} module provides utility
|
5
|
+
# methods that are internal to Ryo. This module
|
6
|
+
# and its methods should not be used directly.
|
7
|
+
# @api private
|
8
|
+
module Ryo::Utils
|
9
|
+
private
|
10
|
+
|
11
|
+
##
|
12
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
13
|
+
# A Ryo object
|
14
|
+
# @param [<String, Symbol>] method
|
15
|
+
# The name of a method
|
16
|
+
# @param [Proc] b
|
17
|
+
# The method's implementation
|
18
|
+
def define_method!(ryo, method, &b)
|
19
|
+
kernel(:define_singleton_method)
|
20
|
+
.bind_call(ryo, method, &b)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
25
|
+
# A Ryo object
|
26
|
+
# @param [<String, #to_s>] property
|
27
|
+
# The name of a property
|
28
|
+
# @return [Boolean]
|
29
|
+
# Returns true for a Ryo property that has a
|
30
|
+
# corresponding getter method implemented by Ryo
|
31
|
+
def getter_defined?(ryo, property)
|
32
|
+
path = kernel(:method)
|
33
|
+
.bind_call(ryo, property)
|
34
|
+
.source_location
|
35
|
+
&.dig(0)
|
36
|
+
path ? File.dirname(path) == File.dirname(__FILE__) : false
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
41
|
+
# A Ryo object
|
42
|
+
# @param [<String, #to_s>] property
|
43
|
+
# The name of a property
|
44
|
+
# @return [Boolean]
|
45
|
+
# Returns true for a Ryo property that has a
|
46
|
+
# corresponding setter method implemented by Ryo
|
47
|
+
def setter_defined?(ryo, property)
|
48
|
+
getter_defined?(ryo, "#{property}=")
|
49
|
+
end
|
50
|
+
|
51
|
+
def merge!(obj1, obj2)
|
52
|
+
obj1, obj2 = to_hash(obj1), to_hash(obj2)
|
53
|
+
obj2.each { obj1[_1.to_s] = _2 }
|
54
|
+
obj1
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_hash(obj)
|
58
|
+
if ryo?(obj)
|
59
|
+
table_of(obj)
|
60
|
+
else
|
61
|
+
Hash.try_convert(obj)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def kernel(name)
|
66
|
+
Module.instance_method(name)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo::YAML Ryo::YAML} module provides a number of methods
|
5
|
+
# for coercing YAML data into a Ryo object. It must be required
|
6
|
+
# separately to Ryo (ie: require "ryo/yaml"), and the methods of
|
7
|
+
# this module are then available on the {Ryo Ryo} module.
|
8
|
+
module Ryo::YAML
|
9
|
+
require "yaml"
|
10
|
+
extend self
|
11
|
+
|
12
|
+
##
|
13
|
+
# @example
|
14
|
+
# Ryo.from_yaml(path: "/foo/bar/baz.yaml")
|
15
|
+
# Ryo.from_yaml(string: "---\nfoo: bar\n")
|
16
|
+
#
|
17
|
+
# @param [String] path
|
18
|
+
# The path to a YAML file
|
19
|
+
#
|
20
|
+
# @param [String] string
|
21
|
+
# A blob of YAML
|
22
|
+
#
|
23
|
+
# @param [Ryo] object
|
24
|
+
# {Ryo::Object Ryo::Object}, or {Ryo::BasicObject Ryo::BasicObject}
|
25
|
+
# Defaults to {Ryo::Object Ryo::Object}
|
26
|
+
#
|
27
|
+
# @raise [SystemCallError]
|
28
|
+
# Might raise a number of Errno exceptions
|
29
|
+
#
|
30
|
+
# @return [Ryo::Object, Ryo::BasicObject]
|
31
|
+
# Returns a Ryo object
|
32
|
+
def from_yaml(path: nil, string: nil, object: Ryo::Object)
|
33
|
+
if path && string
|
34
|
+
raise ArgumentError, "Provide a path or string but not both"
|
35
|
+
elsif path
|
36
|
+
object.from YAML.load_file(path)
|
37
|
+
elsif string
|
38
|
+
object.from YAML.load(string)
|
39
|
+
else
|
40
|
+
raise ArgumentError, "No path or string provided"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Ryo.extend(self)
|
45
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The {Ryo Ryo} module implements most of its behavior as singleton methods
|
5
|
+
# that are inherited from the {Ryo::Reflect Ryo::Reflect}, and
|
6
|
+
# {Ryo::Keywords Ryo:Keywords} modules.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # Ryo.delete
|
10
|
+
# point = Ryo(x: 0, y: 0)
|
11
|
+
# Ryo.delete(point, "x")
|
12
|
+
# point.x # => nil
|
13
|
+
#
|
14
|
+
# # Ryo.assign
|
15
|
+
# point = Ryo.assign(Ryo({}), {x: 0}, {y: 0})
|
16
|
+
# point.x # => 0
|
17
|
+
module Ryo
|
18
|
+
require_relative "ryo/utils"
|
19
|
+
require_relative "ryo/reflect"
|
20
|
+
require_relative "ryo/keywords"
|
21
|
+
require_relative "ryo/builder"
|
22
|
+
require_relative "ryo/basic_object"
|
23
|
+
require_relative "ryo/object"
|
24
|
+
require_relative "ryo/function"
|
25
|
+
require_relative "ryo/memo"
|
26
|
+
require_relative "ryo/enumerable"
|
27
|
+
|
28
|
+
extend Ryo::Reflect
|
29
|
+
extend Ryo::Keywords
|
30
|
+
extend Ryo::Enumerable
|
31
|
+
|
32
|
+
##
|
33
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
34
|
+
# A Ryo object
|
35
|
+
# @param [Module] mod
|
36
|
+
# The module to extend a Ryo object with
|
37
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
38
|
+
# Returns an extended Ryo object
|
39
|
+
def self.extend!(ryo, mod)
|
40
|
+
kernel(:extend).bind_call(ryo, mod)
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Duplicates a Ryo object, and its prototype(s).
|
45
|
+
#
|
46
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
47
|
+
# A Ryo object
|
48
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
49
|
+
# Returns a duplicated Ryo object
|
50
|
+
def self.dup(ryo)
|
51
|
+
duplicate = extend!(
|
52
|
+
kernel(:dup).bind_call(ryo),
|
53
|
+
self
|
54
|
+
)
|
55
|
+
if proto = prototype_of(duplicate)
|
56
|
+
set_prototype_of(duplicate, dup(proto))
|
57
|
+
end
|
58
|
+
duplicate
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Creates a memoized Ryo value
|
63
|
+
#
|
64
|
+
# @param [Proc] b
|
65
|
+
# A Proc that is memoized after being accessed for the first time
|
66
|
+
# @return [Ryo::Memo]
|
67
|
+
# Returns an instance of {Ryo::Memo Ryo::Memo}
|
68
|
+
def self.memo(&b)
|
69
|
+
Ryo::Memo.new(&b)
|
70
|
+
end
|
71
|
+
class << Ryo
|
72
|
+
alias_method :lazy, :memo
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Creates a Ryo object by recursively walking a Hash object
|
77
|
+
#
|
78
|
+
# @param props (see Ryo::Builder.build)
|
79
|
+
# @param prototype (see Ryo::Builder.build)
|
80
|
+
# @return [Ryo::Object]
|
81
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
82
|
+
def self.from(props, prototype = nil)
|
83
|
+
Ryo::Object.from(props, prototype)
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# @return [<Ryo::Object, Ryo::BasicObject>, nil]
|
88
|
+
# Returns the prototype of self, or nil if self has no prototype
|
89
|
+
def __proto__
|
90
|
+
@_proto
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# @note
|
95
|
+
# This method will first look for a property on self,
|
96
|
+
# and if it is not found then it will forward the query
|
97
|
+
# onto `Ryo#__proto__`
|
98
|
+
# @param [String] property
|
99
|
+
# The name of a property
|
100
|
+
# @return [<Object, BasicObject>, nil]
|
101
|
+
# Returns the property's value, or nil
|
102
|
+
def [](property)
|
103
|
+
property = property.to_s
|
104
|
+
if Ryo.property?(self, property)
|
105
|
+
v = @_table[property]
|
106
|
+
Ryo.memo?(v) ? self[property] = v.call : v
|
107
|
+
else
|
108
|
+
return unless @_proto
|
109
|
+
Ryo.call_method(@_proto, property)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Assign a property
|
115
|
+
#
|
116
|
+
# @param [String] property
|
117
|
+
# The name of a property
|
118
|
+
# @param [<Object,BasicObject>] value
|
119
|
+
# @return [void]
|
120
|
+
def []=(property, value)
|
121
|
+
Ryo.define_property(self, property.to_s, value)
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# @param [<Ryo::Object, Ryo::BasicObject>, Hash, #to_h] other
|
126
|
+
# @return [Boolean]
|
127
|
+
# Returns true **other** is equal to self
|
128
|
+
def ==(other)
|
129
|
+
if Ryo.ryo?(other)
|
130
|
+
@_table == Ryo.table_of(other)
|
131
|
+
else
|
132
|
+
other = Hash.try_convert(other)
|
133
|
+
return false unless other
|
134
|
+
@_table == other.map { [_1.to_s, _2] }.to_h
|
135
|
+
end
|
136
|
+
end
|
137
|
+
alias_method :eql?, :==
|
138
|
+
|
139
|
+
##
|
140
|
+
# @return [String]
|
141
|
+
# Returns a String representation of a Ryo object
|
142
|
+
def inspect
|
143
|
+
Ryo.inspect_object(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# @return [Hash]
|
148
|
+
# Returns the lookup table of a Ryo object
|
149
|
+
def to_h
|
150
|
+
Ryo.table_of(self, recursive: true)
|
151
|
+
end
|
152
|
+
alias_method :to_hash, :to_h
|
153
|
+
|
154
|
+
##
|
155
|
+
# @private
|
156
|
+
def pretty_print(q)
|
157
|
+
q.text(inspect)
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# @private
|
162
|
+
def respond_to?(property, include_all = false)
|
163
|
+
respond_to_missing?(property, include_all)
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# @private
|
168
|
+
def respond_to_missing?(property, include_all = false)
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# @private
|
174
|
+
def method_missing(name, *args, &b)
|
175
|
+
property = name.to_s
|
176
|
+
if property[-1] == "="
|
177
|
+
property = property[0..-2]
|
178
|
+
self[property] = args.first
|
179
|
+
elsif Ryo.property?(self, property)
|
180
|
+
self[property]
|
181
|
+
elsif @_proto
|
182
|
+
Ryo.call_method(@_proto, name, *args, &b)
|
183
|
+
.tap { _1.bind!(self) if Ryo.function?(_1) }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
##
|
189
|
+
# @param props (see Ryo::Builder.build)
|
190
|
+
# @param prototype (see Ryo::Builder.build)
|
191
|
+
# @return [Ryo::Object]
|
192
|
+
# Returns a Ryo object
|
193
|
+
def Ryo(props, prototype = nil)
|
194
|
+
Ryo::Object.create(props, prototype)
|
195
|
+
end
|
data/share/quran-audio/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
v0.4.
|
1
|
+
v0.4.2
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quran-audio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- '0x1eef'
|
@@ -119,6 +119,21 @@ files:
|
|
119
119
|
- LICENSE
|
120
120
|
- README.md
|
121
121
|
- bin/quran-audio
|
122
|
+
- bundle/io-line.rb/lib/io/line.rb
|
123
|
+
- bundle/io-line.rb/lib/io/line/multiple.rb
|
124
|
+
- bundle/ryo.rb/lib/ryo.rb
|
125
|
+
- bundle/ryo.rb/lib/ryo/basic_object.rb
|
126
|
+
- bundle/ryo.rb/lib/ryo/builder.rb
|
127
|
+
- bundle/ryo.rb/lib/ryo/enumerable.rb
|
128
|
+
- bundle/ryo.rb/lib/ryo/function.rb
|
129
|
+
- bundle/ryo.rb/lib/ryo/json.rb
|
130
|
+
- bundle/ryo.rb/lib/ryo/keywords.rb
|
131
|
+
- bundle/ryo.rb/lib/ryo/memo.rb
|
132
|
+
- bundle/ryo.rb/lib/ryo/object.rb
|
133
|
+
- bundle/ryo.rb/lib/ryo/reflect.rb
|
134
|
+
- bundle/ryo.rb/lib/ryo/utils.rb
|
135
|
+
- bundle/ryo.rb/lib/ryo/version.rb
|
136
|
+
- bundle/ryo.rb/lib/ryo/yaml.rb
|
122
137
|
- lib/quran/audio.rb
|
123
138
|
- lib/quran/audio/command.rb
|
124
139
|
- lib/quran/audio/command/ls.rb
|