quran-audio 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4f6bb534d549b8f15007767b977d02ba66bb99b29230d208cd025beef58156e
4
- data.tar.gz: fcf08060b5f19fc4404cf8620f3c4acde6e936f6080ecc5ee36f266eaa0a4f11
3
+ metadata.gz: f31510aaf2b2ac45001870411b82eb1e1ff7c8103cdbebb4f9b92268906b4cfb
4
+ data.tar.gz: 6c54cbdf7ed5493fcb9cc0cf0e84305adae279c2433d5f1e6204ac9ba9af9b38
5
5
  SHA512:
6
- metadata.gz: b470c6fc24757c9f77702dd1516a2ea13b853169cd8838515c911d8d9ed2c4cebccb7c502fec64df657badebb82f5f1870e3dcecce314e9e1c9e5ebf4ae69bbc
7
- data.tar.gz: 0ade0f5665a4e42b2811ce6582a62ab4162954eccceee2084a8eccc2a98d59b2accae844a113fa1a4c1b71f03248291be66e0e42efc99e3c3d48b6eebb5ee5b9
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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Ryo::Memo < Ryo::Function
4
+ 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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ryo
4
+ VERSION = "0.5.6"
5
+ 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
@@ -1 +1 @@
1
- v0.4.0
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.0
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