matchable 0.1.0 → 0.1.1
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 +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/benchmarks/dynamic_vs_generated_benchmark.rb +136 -0
- data/benchmarks/dynamic_vs_generated_benchmark_results.txt +55 -0
- data/lib/matchable.rb +154 -35
- data/lib/matchable/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea2b5bef957487e83b056970242e39508465ae5b3a4b466e881a71c8d235e7fd
|
4
|
+
data.tar.gz: 0d00fac4bda33448af11fdde57ee9bb010d1b50ff0be881084dea7a26d1b6dd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f6cbb7043d57f74cb6131b536e277882aafaae7e05885ad79e7155707f236dd13263853f3ed212f0976f2fdd8e8ce1c21e2607504943a82b69f82fc56681b38
|
7
|
+
data.tar.gz: 78eed8f187eb98ef08c46fda76280123004b122c30a13d46ae9cab1bc412a8a66f3f266b5db808ebcd0d948e87af26090cf53f814c093e50dcaa1d26e416e545
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.0
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
matchable (0.1.
|
4
|
+
matchable (0.1.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
benchmark-ips (2.8.4)
|
9
10
|
coderay (1.1.3)
|
10
11
|
diff-lcs (1.4.4)
|
11
12
|
ffi (1.14.2)
|
@@ -60,6 +61,7 @@ PLATFORMS
|
|
60
61
|
x86_64-darwin-19
|
61
62
|
|
62
63
|
DEPENDENCIES
|
64
|
+
benchmark-ips
|
63
65
|
guard-rspec
|
64
66
|
matchable!
|
65
67
|
rake (~> 13.0)
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/usr/bin/env ruby -W0
|
2
|
+
|
3
|
+
require 'matchable'
|
4
|
+
require 'benchmark/ips'
|
5
|
+
|
6
|
+
class PersonMacro
|
7
|
+
include Matchable
|
8
|
+
|
9
|
+
deconstruct :new
|
10
|
+
deconstruct_keys :name, :age
|
11
|
+
|
12
|
+
attr_reader :name, :age
|
13
|
+
|
14
|
+
def initialize(name, age)
|
15
|
+
@name = name
|
16
|
+
@age = age
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class PersonDynamic
|
21
|
+
VALID_KEYS = %i(name age)
|
22
|
+
|
23
|
+
attr_reader :name, :age
|
24
|
+
|
25
|
+
def initialize(name, age)
|
26
|
+
@name = name
|
27
|
+
@age = age
|
28
|
+
end
|
29
|
+
|
30
|
+
def deconstruct() = VALID_KEYS.map { public_send(_1) }
|
31
|
+
|
32
|
+
def deconstruct_keys(keys)
|
33
|
+
valid_keys = keys ? VALID_KEYS & keys : VALID_KEYS
|
34
|
+
valid_keys.to_h { [_1, public_send(_1)] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
alice_macro = PersonMacro.new('Alice', 42)
|
39
|
+
alice_dynamic = PersonDynamic.new('Alice', 42)
|
40
|
+
|
41
|
+
Benchmark.ips do |x|
|
42
|
+
x.report("[Person] Macro Generated - Full Hash") do
|
43
|
+
alice_macro in { name: /^A/, age: 30.. }
|
44
|
+
end
|
45
|
+
|
46
|
+
x.report("[Person] Macro Generated - Partial Hash") do
|
47
|
+
alice_macro in { name: /^A/ }
|
48
|
+
end
|
49
|
+
|
50
|
+
x.report("[Person] Macro Generated - Array") do
|
51
|
+
alice_macro in [/^A/, 30..]
|
52
|
+
end
|
53
|
+
|
54
|
+
x.report("[Person] Dynamic Generated - Full Hash") do
|
55
|
+
alice_dynamic in { name: /^A/, age: 30.. }
|
56
|
+
end
|
57
|
+
|
58
|
+
x.report("[Person] Dynamic Generated - Partial Hash") do
|
59
|
+
alice_dynamic in { name: /^A/ }
|
60
|
+
end
|
61
|
+
|
62
|
+
x.report("[Person] Dynamic Generated - Array") do
|
63
|
+
alice_dynamic in [/^A/, 30..]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
puts '', '-' * 80, ''
|
68
|
+
|
69
|
+
# 26 attributes, should be enough to stress things out
|
70
|
+
LETTERS = ('a'..'z').to_a.map(&:to_sym)
|
71
|
+
LETTER_IVARS = LETTERS.map { "@#{_1} = #{_1}" }.join("\n")
|
72
|
+
LETTER_VALUES = LETTERS.each_with_index.to_h
|
73
|
+
|
74
|
+
# Easier than typing 26 attrs
|
75
|
+
eval <<~RUBY
|
76
|
+
class BigAttrMacro
|
77
|
+
include Matchable
|
78
|
+
|
79
|
+
deconstruct :new
|
80
|
+
deconstruct_keys *LETTERS
|
81
|
+
|
82
|
+
attr_reader *LETTERS
|
83
|
+
|
84
|
+
def initialize(#{LETTERS.join(', ')})
|
85
|
+
#{LETTER_IVARS}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
RUBY
|
89
|
+
|
90
|
+
eval <<~RUBY
|
91
|
+
class BigAttrDynamic
|
92
|
+
VALID_KEYS = LETTERS
|
93
|
+
|
94
|
+
attr_reader *LETTERS
|
95
|
+
|
96
|
+
def initialize(#{LETTERS.join(', ')})
|
97
|
+
#{LETTER_IVARS}
|
98
|
+
end
|
99
|
+
|
100
|
+
def deconstruct() = VALID_KEYS.map { public_send(_1) }
|
101
|
+
|
102
|
+
def deconstruct_keys(keys)
|
103
|
+
valid_keys = keys ? VALID_KEYS & keys : VALID_KEYS
|
104
|
+
valid_keys.to_h { [_1, public_send(_1)] }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
RUBY
|
108
|
+
|
109
|
+
big_attr_macro = BigAttrMacro.new(*1..26)
|
110
|
+
big_attr_dynamic = BigAttrDynamic.new(*1..26)
|
111
|
+
|
112
|
+
Benchmark.ips do |x|
|
113
|
+
x.report("[BigAttr] Macro Generated - Full Hash") do
|
114
|
+
big_attr_macro in {}
|
115
|
+
end
|
116
|
+
|
117
|
+
x.report("[BigAttr] Macro Generated - Partial Hash") do
|
118
|
+
big_attr_macro in { a:, b:, c:, d:, e:, f: }
|
119
|
+
end
|
120
|
+
|
121
|
+
x.report("[BigAttr] Macro Generated - Array") do
|
122
|
+
big_attr_macro in [1, 2, 3, *]
|
123
|
+
end
|
124
|
+
|
125
|
+
x.report("[BigAttr] Dynamic Generated - Full Hash") do
|
126
|
+
big_attr_dynamic in {}
|
127
|
+
end
|
128
|
+
|
129
|
+
x.report("[BigAttr] Dynamic Generated - Partial Hash") do
|
130
|
+
big_attr_dynamic in { a:, b:, c:, d:, e:, f: }
|
131
|
+
end
|
132
|
+
|
133
|
+
x.report("[BigAttr] Dynamic Generated - Array") do
|
134
|
+
big_attr_dynamic in [1, 2, 3, *]
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
Warming up --------------------------------------
|
2
|
+
[Person] Macro Generated - Full Hash
|
3
|
+
108.660k i/100ms
|
4
|
+
[Person] Macro Generated - Partial Hash
|
5
|
+
150.641k i/100ms
|
6
|
+
[Person] Macro Generated - Array
|
7
|
+
209.579k i/100ms
|
8
|
+
[Person] Dynamic Generated - Full Hash
|
9
|
+
102.585k i/100ms
|
10
|
+
[Person] Dynamic Generated - Partial Hash
|
11
|
+
154.093k i/100ms
|
12
|
+
[Person] Dynamic Generated - Array
|
13
|
+
136.640k i/100ms
|
14
|
+
Calculating -------------------------------------
|
15
|
+
[Person] Macro Generated - Full Hash
|
16
|
+
1.104M (± 3.0%) i/s - 5.542M in 5.025098s
|
17
|
+
[Person] Macro Generated - Partial Hash
|
18
|
+
1.657M (± 1.8%) i/s - 8.436M in 5.093239s
|
19
|
+
[Person] Macro Generated - Array
|
20
|
+
2.101M (± 3.8%) i/s - 10.689M in 5.095977s
|
21
|
+
[Person] Dynamic Generated - Full Hash
|
22
|
+
998.994k (± 2.1%) i/s - 5.027M in 5.033974s
|
23
|
+
[Person] Dynamic Generated - Partial Hash
|
24
|
+
1.484M (± 3.6%) i/s - 7.551M in 5.093305s
|
25
|
+
[Person] Dynamic Generated - Array
|
26
|
+
1.421M (± 2.5%) i/s - 7.105M in 5.002556s
|
27
|
+
|
28
|
+
--------------------------------------------------------------------------------
|
29
|
+
|
30
|
+
Warming up --------------------------------------
|
31
|
+
[BigAttr] Macro Generated - Full Hash
|
32
|
+
62.462k i/100ms
|
33
|
+
[BigAttr] Macro Generated - Partial Hash
|
34
|
+
57.960k i/100ms
|
35
|
+
[BigAttr] Macro Generated - Array
|
36
|
+
159.136k i/100ms
|
37
|
+
[BigAttr] Dynamic Generated - Full Hash
|
38
|
+
19.686k i/100ms
|
39
|
+
[BigAttr] Dynamic Generated - Partial Hash
|
40
|
+
52.946k i/100ms
|
41
|
+
[BigAttr] Dynamic Generated - Array
|
42
|
+
29.178k i/100ms
|
43
|
+
Calculating -------------------------------------
|
44
|
+
[BigAttr] Macro Generated - Full Hash
|
45
|
+
644.864k (± 5.9%) i/s - 3.248M in 5.054710s
|
46
|
+
[BigAttr] Macro Generated - Partial Hash
|
47
|
+
580.784k (± 3.4%) i/s - 2.956M in 5.096195s
|
48
|
+
[BigAttr] Macro Generated - Array
|
49
|
+
1.568M (± 4.0%) i/s - 7.957M in 5.082464s
|
50
|
+
[BigAttr] Dynamic Generated - Full Hash
|
51
|
+
194.429k (± 3.2%) i/s - 984.300k in 5.068253s
|
52
|
+
[BigAttr] Dynamic Generated - Partial Hash
|
53
|
+
518.690k (± 3.7%) i/s - 2.594M in 5.008953s
|
54
|
+
[BigAttr] Dynamic Generated - Array
|
55
|
+
295.488k (± 2.1%) i/s - 1.488M in 5.038268s
|
data/lib/matchable.rb
CHANGED
@@ -5,9 +5,30 @@ require_relative "matchable/version"
|
|
5
5
|
# Interface for Pattern Matching hooks
|
6
6
|
#
|
7
7
|
# @author baweaver
|
8
|
-
# @since 0.0
|
8
|
+
# @since 0.1.0
|
9
9
|
#
|
10
10
|
module Matchable
|
11
|
+
# Nicety wrapper to ensure unmatched methods give a clear response on what's
|
12
|
+
# missing
|
13
|
+
#
|
14
|
+
# @author baweaver
|
15
|
+
# @since 0.1.1
|
16
|
+
#
|
17
|
+
class UnmatchedName < StandardError
|
18
|
+
def initialize(msg)
|
19
|
+
@msg = <<~ERROR
|
20
|
+
Some attributes are missing methods for the match. Ensure all attributes
|
21
|
+
have a method of the same name, or an `attr_` method.
|
22
|
+
|
23
|
+
Original Error: #{msg}
|
24
|
+
ERROR
|
25
|
+
|
26
|
+
super(@msg)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
DeconstructedBranch = Struct.new(:method_name, :code_branch, :guard_condition)
|
31
|
+
|
11
32
|
# Constant to prepend methods and extensions to
|
12
33
|
MODULE_NAME = "MatchableDeconstructors".freeze
|
13
34
|
|
@@ -17,7 +38,7 @@ module Matchable
|
|
17
38
|
# Class method hooks for adding pattern matching interfaces
|
18
39
|
#
|
19
40
|
# @author baweaver
|
20
|
-
# @since 0.0
|
41
|
+
# @since 0.1.0
|
21
42
|
module ClassMethods
|
22
43
|
# Hook for the `deconstruct` instance method which triggers its definition
|
23
44
|
# based on a deconstruction method passed. If the method is not yet defined
|
@@ -28,12 +49,12 @@ module Matchable
|
|
28
49
|
#
|
29
50
|
# @return [Array[status, method_name]]
|
30
51
|
def deconstruct(method_name)
|
31
|
-
return if
|
52
|
+
return if matchable_module.const_defined?("MATCHABLE_METHOD")
|
32
53
|
|
33
54
|
# :new should mean :initialize if one wants to match against arguments
|
34
55
|
# to :new
|
35
56
|
method_name = :initialize if method_name == :new
|
36
|
-
|
57
|
+
matchable_module.const_set("MATCHABLE_METHOD", method_name)
|
37
58
|
|
38
59
|
# If this was called after the method was added, go ahead and attach,
|
39
60
|
# otherwise we need some trickery to make sure the method is defined
|
@@ -77,26 +98,76 @@ module Matchable
|
|
77
98
|
# @return [void]
|
78
99
|
def deconstruct_keys(*keys)
|
79
100
|
# Return early if called more than once
|
80
|
-
return if
|
101
|
+
return if matchable_module.const_defined?('MATCHABLE_KEYS')
|
81
102
|
|
82
103
|
# Ensure keys are symbols, then generate Ruby code for each
|
83
104
|
# key assignment branch to be used below
|
84
|
-
sym_keys
|
85
|
-
deconstructions = sym_keys.map { deconstructed_value(_1) }.join("\n\n")
|
105
|
+
sym_keys = keys.map(&:to_sym)
|
86
106
|
|
87
107
|
# Retain a reference to which keys we deconstruct from
|
88
|
-
|
108
|
+
matchable_module.const_set('MATCHABLE_KEYS', sym_keys)
|
109
|
+
|
110
|
+
# Lazy Hash mapping of all keys to all values wrapped in lazy
|
111
|
+
# procs.
|
112
|
+
#
|
113
|
+
# see: #lazy_match_value
|
114
|
+
matchable_module.const_set('MATCHABLE_LAZY_VALUES', lazy_match_values(sym_keys))
|
89
115
|
|
90
116
|
# `public_send` can be slow, and `to_h` and `each_with_object` can also
|
91
117
|
# be slow. This defines the direct method calls in-line to prevent
|
92
118
|
# any performance penalties to generate optimal match code.
|
93
|
-
|
119
|
+
#
|
120
|
+
# This generates and adds a method to the prepended module. We add YARDoc
|
121
|
+
# to this because the generated source can be seen and we want to be nice.
|
122
|
+
#
|
123
|
+
# We also intercept name errors to give more useful errors should it
|
124
|
+
# be implemented incorrectly.
|
125
|
+
matchable_module.class_eval <<~RUBY, __FILE__ , __LINE__ + 1
|
126
|
+
# Pattern Matching hooks for hash-like matches.
|
127
|
+
#
|
128
|
+
# This method was generated by Matchable. Make sure all properties have
|
129
|
+
# associated methods attached or this will raise an error.
|
130
|
+
#
|
131
|
+
# @param keys [Array[Symbol]]
|
132
|
+
# Keys to limit the deconstruction to. If keys are `nil` then return
|
133
|
+
# all possible keys instead.
|
134
|
+
#
|
135
|
+
# @return [Hash[Symbol, Any]]
|
136
|
+
# Deconstructed keys and values
|
94
137
|
def deconstruct_keys(keys)
|
138
|
+
# If `keys` is `nil` we want to return all possible keys. This
|
139
|
+
# generates all of them as a direct Hash representation and
|
140
|
+
# returns that, rather than guard all methods below on
|
141
|
+
# `keys.nil? || ...`.
|
142
|
+
if keys.nil?
|
143
|
+
return {
|
144
|
+
#{nil_guard_values(sym_keys)}
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
# If keys are present, we want to iterate the keys to add requested
|
149
|
+
# values. Before we iterate we also want to ensure only valid keys
|
150
|
+
# are being passed through here.
|
95
151
|
deconstructed_values = {}
|
152
|
+
valid_keys = MATCHABLE_KEYS & keys
|
96
153
|
|
97
|
-
#
|
154
|
+
# This is where things get interesting. Each value is retrieved through
|
155
|
+
# a lazy hash in which `method_name or `key` points to a proc:
|
156
|
+
#
|
157
|
+
# key: -> o { o.key }
|
158
|
+
#
|
159
|
+
# The actual method is interpolated directly and `eval`'d to make this
|
160
|
+
# faster than `public_send`.
|
161
|
+
valid_keys.each do |key|
|
162
|
+
deconstructed_values[key] = MATCHABLE_LAZY_VALUES[key].call(self)
|
163
|
+
end
|
98
164
|
|
165
|
+
# ...and once this is done, return back the deconstructed values.
|
99
166
|
deconstructed_values
|
167
|
+
# We rescue `NameError` here to return a more useful message and indicate
|
168
|
+
# there are some missing methods for the match.
|
169
|
+
rescue NameError => e
|
170
|
+
raise Matchable::UnmatchedName, e
|
100
171
|
end
|
101
172
|
RUBY
|
102
173
|
|
@@ -104,26 +175,41 @@ module Matchable
|
|
104
175
|
nil
|
105
176
|
end
|
106
177
|
|
107
|
-
# Generates
|
108
|
-
#
|
109
|
-
# similar methods.
|
178
|
+
# Generates key-value pairs of `method_name` pointing to `method_name` for
|
179
|
+
# the case where `keys` is `nil`, requiring all keys to be directly returned.
|
110
180
|
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
# hence adding this guard in every case.
|
114
|
-
#
|
115
|
-
# @param method_name [Symbol]
|
116
|
-
# Name of the method to add a deconstructed key from
|
181
|
+
# @param method_names [Array[Symbol]]
|
182
|
+
# Names of the methods
|
117
183
|
#
|
118
184
|
# @return [String]
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
185
|
+
# Ruby code for all key-value pairs for method names
|
186
|
+
def nil_guard_values(method_names)
|
187
|
+
method_names
|
188
|
+
.map { |method_name| "#{method_name}: #{method_name}" }
|
189
|
+
.join(",\n")
|
190
|
+
end
|
191
|
+
|
192
|
+
# Generated Ruby Hash based on a mapping of valid keys to a lazy function
|
193
|
+
# to retrieve them directly without the need for `public_send` or similar
|
194
|
+
# methods. This code instead directly interpolates the method call and
|
195
|
+
# evaluates that, but will not run the code until called as a proc in the
|
196
|
+
# actual `deconstruct_keys` method.
|
197
|
+
#
|
198
|
+
# @param method_names [Array[Symbol]]
|
199
|
+
# Names of the methods
|
200
|
+
#
|
201
|
+
# @return [Hash[Symbol, Proc]]
|
202
|
+
# Mapping of deconstruction key to lazy retrieval function
|
203
|
+
def lazy_match_values(method_names)
|
204
|
+
method_names
|
205
|
+
# Name of the method points to a lazy function to retrieve it
|
206
|
+
.map { |method_name| " #{method_name}: -> o { o.#{method_name} }," }
|
207
|
+
# Join them into one String
|
208
|
+
.join("\n")
|
209
|
+
# Wrap them in Hash brackets
|
210
|
+
.then { |kv_pairs| "{\n#{kv_pairs}\n}"}
|
211
|
+
# ...and `eval` it to turn it into a Hash
|
212
|
+
.then { |ruby_code| eval ruby_code }
|
127
213
|
end
|
128
214
|
|
129
215
|
# Attaches the deconstructor to the parent class. If the method is
|
@@ -138,27 +224,60 @@ module Matchable
|
|
138
224
|
private def attach_deconstructor(method_name)
|
139
225
|
i_method = instance_method(method_name)
|
140
226
|
|
141
|
-
deconstruction_code =
|
142
|
-
|
227
|
+
deconstruction_code =
|
228
|
+
# If the method is `initialize` we want to treat it differently, as
|
229
|
+
# it represents a unique destructuring based on the method's parameters.
|
230
|
+
if method_name == :initialize
|
231
|
+
# Example of parameters:
|
232
|
+
#
|
233
|
+
# -> a, b = 2, *c, d:, e: 3, **f, &fn {}.parameters
|
234
|
+
# # => [
|
235
|
+
# # [:req, :a], [:opt, :b], [:rest, :c], [:keyreq, :d], [:key, :e],
|
236
|
+
# # [:keyrest, :f], [:block, :fn]
|
237
|
+
# # ]
|
238
|
+
#
|
239
|
+
# The `last` of each is the name of the param. This assumes a tied
|
240
|
+
# method to each of these names, and will fail otherwise.
|
241
|
+
param_names = i_method.parameters.map(&:last)
|
143
242
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
243
|
+
# Take the literal names of those parameters and treat them like
|
244
|
+
# method calls to have the entire thing inlined
|
245
|
+
"[#{param_names.join(', ')}]"
|
246
|
+
# Otherwise we just want the method name, don't do anything special to
|
247
|
+
# this. If you have any other methods that might make sense here let me
|
248
|
+
# know by filing an issue.
|
249
|
+
else
|
250
|
+
method_name
|
251
|
+
end
|
148
252
|
|
149
|
-
|
253
|
+
# Then we evaluate that in the context of our prepended module and away
|
254
|
+
# we go with our new method. Added YARDoc because this will show up in the
|
255
|
+
# actual code and we want to be nice.
|
256
|
+
matchable_module.class_eval <<~RUBY, __FILE__ , __LINE__ + 1
|
257
|
+
# Pattern Matching hook for array-like deconstruction methods.
|
258
|
+
#
|
259
|
+
# This method was generated by Matchable and based on the `#{method_name}`
|
260
|
+
# method. Make sure all properties have associated methods attached or
|
261
|
+
# this will raise an error.
|
262
|
+
#
|
263
|
+
# @return [Array]
|
150
264
|
def deconstruct
|
151
265
|
#{deconstruction_code}
|
266
|
+
# We rescue `NameError` here to return a more useful message and indicate
|
267
|
+
# there are some missing methods for the match.
|
268
|
+
rescue NameError => e
|
269
|
+
raise Matchable::UnmatchedName, e
|
152
270
|
end
|
153
271
|
RUBY
|
154
272
|
|
273
|
+
# Return back nil because this value really should not be relied upon
|
155
274
|
nil
|
156
275
|
end
|
157
276
|
|
158
277
|
# Prepended module to define methods against
|
159
278
|
#
|
160
279
|
# @return [Module]
|
161
|
-
private def
|
280
|
+
private def matchable_module
|
162
281
|
if const_defined?(MODULE_NAME)
|
163
282
|
const_get(MODULE_NAME)
|
164
283
|
else
|
data/lib/matchable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matchable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Weaver
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01
|
11
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -20,6 +20,7 @@ files:
|
|
20
20
|
- ".github/workflows/main.yml"
|
21
21
|
- ".gitignore"
|
22
22
|
- ".rspec"
|
23
|
+
- ".ruby-version"
|
23
24
|
- CODE_OF_CONDUCT.md
|
24
25
|
- Gemfile
|
25
26
|
- Gemfile.lock
|
@@ -27,6 +28,8 @@ files:
|
|
27
28
|
- LICENSE.txt
|
28
29
|
- README.md
|
29
30
|
- Rakefile
|
31
|
+
- benchmarks/dynamic_vs_generated_benchmark.rb
|
32
|
+
- benchmarks/dynamic_vs_generated_benchmark_results.txt
|
30
33
|
- bin/console
|
31
34
|
- bin/setup
|
32
35
|
- lib/matchable.rb
|