matchable 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|