props_template 1.0.0.alpha.4 → 1.0.0

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: dd22916bd76997bbac899cc2c7f3ee1dde0de4d757d508bde300c665fefffed2
4
- data.tar.gz: 3ed18e6266e026ba545b5389cd70ebd215e825be1aa268afd3510a1c695a633f
3
+ metadata.gz: 6e8ec3d3579ed65bb2a927d2bf7abb10c9e5f4ee4d5a5147da09e8efb1e6a030
4
+ data.tar.gz: f21d46d7b34d47ee191b0ddcfe68ceb506d15d316a4ad00e433ca3752d82045a
5
5
  SHA512:
6
- metadata.gz: e036c21457b476fb4554d7d5e5420a88659da3767750eaa70cabc05bd8f5c6924d23aaeb7e76e3640bf8d05558c2b6ac8e1eed9e4cf437d8f19e3960495cb199
7
- data.tar.gz: cc7a63fc308d9b3c5e3c3c49286cf7c69e06d76eca3d51c04255eebf68c8158f44d76768396b1f0750adc204d0cae75dc7bfeb1cebd14e806bf690b50013f02e
6
+ metadata.gz: db8bb1f529058a5dc7f2be56fe29720f638194e756a229da90deb85b3b885cd8de56dab5609219c73df23d1fe4de2cb80a2edc8803bce6a550ee8a4f16c36f70
7
+ data.tar.gz: dc997a26a9e941c8468e8b1cf755cb3c81e6b541ca7c56661f3ecaab8a701fed67712fd368e1cea50eb8b3dba76238ae169b3b8abb6e2e07485b5a8349ba5673
data/README.md CHANGED
@@ -14,6 +14,49 @@ that other libraries perform by using Oj's `StringWriter` in `rails` mode.
14
14
 
15
15
  ![benchmarks](docs/benchmarks.png)
16
16
 
17
+ It's really fast.
18
+
19
+ `props_template` is second only to `panko` while being feature packed. The
20
+ `Props::Base` [class](./lib/props_template/base.rb) that be used standalone
21
+ is the fastest among all JSON serializers. Results derived from [alba benchmarks](https://github.com/thoughtbot/alba/tree/main/benchmark).
22
+
23
+ ```
24
+ props_base_class: 1439.9 i/s
25
+ panko: 1287.6 i/s - 1.12x slower
26
+ props_template: 998.8 i/s - 1.44x slower
27
+ turbostreamer: 912.9 i/s - 1.58x slower
28
+ alba: 871.0 i/s - 1.65x slower
29
+ jserializer: 668.7 i/s - 2.15x slower
30
+ alba_with_transformation: 604.2 i/s - 2.38x slower
31
+ barley: 452.2 i/s - 3.18x slower
32
+ barley_cache: 441.4 i/s - 3.26x slower
33
+ jbuilder: 432.6 i/s - 3.33x slower
34
+ fast_serializer: 390.1 i/s - 3.69x slower
35
+ rails: 374.1 i/s - 3.85x slower
36
+ rabl: 310.3 i/s - 4.64x slower
37
+ blueprinter: 268.4 i/s - 5.36x slower
38
+ representable: 187.2 i/s - 7.69x slower
39
+ simple_ams: 124.5 i/s - 11.57x slower
40
+ ams: 41.5 i/s - 34.67x slower
41
+ alba_inline: 10.9 i/s - 131.64x slower
42
+
43
+ Gem versions:
44
+ active_model_serializers: 0.10.16
45
+ alba: 3.10.0
46
+ barley: 0.9.0
47
+ blueprinter: 1.2.1
48
+ jbuilder: 2.14.1
49
+ jserializer: 0.2.1
50
+ panko_serializer: 0.8.4
51
+ rabl: 0.17.0
52
+ representable: 3.2.0
53
+ simple_ams: 0.2.6
54
+ turbostreamer: 1.11.0
55
+
56
+ Ruby version: 3.4.8
57
+ Apple M4 Pro
58
+ ```
59
+
17
60
  Caching is fast too.
18
61
 
19
62
  While other libraries spend time unmarshaling,
@@ -105,6 +148,12 @@ json.authorDetails, with.some_option do
105
148
  json.firstName 'David'
106
149
  end
107
150
 
151
+ # or with hash options
152
+
153
+ json.authorDetails, {...options} do
154
+ json.firstName 'David'
155
+ end
156
+
108
157
 
109
158
  # => {"authorDetails": { "firstName": "David" }}
110
159
  ```
@@ -125,6 +174,10 @@ json.set! :firstName, 'David'
125
174
  json.firstName 'David'
126
175
 
127
176
  # => { "firstName": "David" }
177
+
178
+ # or
179
+
180
+ json.postDetails with.partial("blog_post")
128
181
  ```
129
182
 
130
183
  The block form defines key and structure
@@ -340,6 +393,11 @@ with @post, which you can use inside the partial.
340
393
 
341
394
  ```ruby
342
395
  json.one_post(with.partial("posts/blog_post", locals: {post: @post}))
396
+
397
+ # or with hash options
398
+
399
+ json.one_post partial: ["posts/blog_post", locals: {post: @post}] do
400
+ end
343
401
  ```
344
402
 
345
403
  Usage with arrays:
@@ -9,13 +9,17 @@ module Props
9
9
  class InvalidScopeForChildError < StandardError; end
10
10
 
11
11
  class Base
12
+ attr_accessor :item_context
13
+
12
14
  def initialize(encoder = nil)
13
15
  @stream = Oj::StringWriter.new(mode: :rails)
14
16
  @scope = nil
17
+ @item_context = nil
15
18
  end
16
19
 
17
20
  def set_content!(options = {})
18
21
  @scope = nil
22
+ @item_context = nil
19
23
  yield
20
24
  if @scope.nil?
21
25
  @stream.push_object
@@ -59,30 +63,17 @@ module Props
59
63
  nil
60
64
  end
61
65
 
62
- def refine_item_options(item, options)
63
- options
64
- end
65
-
66
66
  def handle_collection_item(collection, item, index, options)
67
+ @item_context = item
68
+
67
69
  set_content!(options) do
68
70
  yield
69
71
  end
70
72
  end
71
73
 
72
- def refine_all_item_options(all_options)
73
- all_options
74
- end
75
-
76
74
  def handle_collection(collection, options)
77
- all_opts = collection.map do |item|
78
- refine_item_options(item, options.clone)
79
- end
80
-
81
- all_opts = refine_all_item_options(all_opts)
82
-
83
75
  collection.each_with_index do |item, index|
84
- pass_opts = all_opts[index]
85
- handle_collection_item(collection, item, index, pass_opts) do
76
+ handle_collection_item(collection, item, index, options) do
86
77
  # todo: remove index?
87
78
  yield item, index
88
79
  end
@@ -29,7 +29,7 @@ module Props
29
29
  def set_content!(options = {})
30
30
  return super if !@em.has_extensions(options)
31
31
 
32
- @em.handle(options) do
32
+ @em.handle(options, item_context) do
33
33
  yield
34
34
  end
35
35
  end
@@ -51,10 +51,6 @@ module Props
51
51
  end
52
52
 
53
53
  def set!(key, options = {}, &block)
54
- if block || options.is_a?(Props::Options)
55
- options = @em.refine_options(options)
56
- end
57
-
58
54
  if !block && options.is_a?(Props::Options)
59
55
  options.valid_for_set!
60
56
  super {}
@@ -78,16 +74,37 @@ module Props
78
74
  nil
79
75
  end
80
76
 
77
+ def handle_collection(collection, options)
78
+ if options[:cache]
79
+ key, rest = [*options[:cache]]
80
+
81
+ if ::Proc === key
82
+ cache_keys = collection.map do |item|
83
+ key.call(item)
84
+ end
85
+ @em.load_cache(cache_keys, rest || {})
86
+ end
87
+ end
88
+
89
+ super
90
+ end
91
+
81
92
  def handle_collection_item(collection, item, index, options)
82
93
  if !options[:key]
83
94
  @traveled_path.push(index)
84
95
  else
85
- id, val = options[:key]
96
+ if (key = options[:key])
97
+ val = if item.respond_to? key
98
+ item.send(key)
99
+ elsif item.is_a? Hash
100
+ item[key] || item[key.to_sym]
101
+ end
102
+ end
86
103
 
87
- if id.nil?
104
+ if key.nil?
88
105
  @traveled_path.push(index)
89
106
  else
90
- @traveled_path.push("#{id}=#{val}")
107
+ @traveled_path.push("#{key}=#{val}")
91
108
  end
92
109
  end
93
110
 
@@ -96,25 +113,5 @@ module Props
96
113
  @traveled_path.pop
97
114
  nil
98
115
  end
99
-
100
- def refine_all_item_options(all_options)
101
- @em.refine_all_item_options(all_options)
102
- end
103
-
104
- def refine_item_options(item, options)
105
- return options if options.empty?
106
-
107
- if (key = options[:key])
108
- val = if item.respond_to? key
109
- item.send(key)
110
- elsif item.is_a? Hash
111
- item[key] || item[key.to_sym]
112
- end
113
-
114
- options[:key] = [options[:key], val]
115
- end
116
-
117
- @em.refine_options(options, item)
118
- end
119
116
  end
120
117
  end
@@ -1,6 +1,9 @@
1
1
  module Props
2
2
  class ExtensionManager
3
- attr_reader :base, :builder, :context
3
+ attr_reader :base, :builder, :context, :cache, :partialer
4
+
5
+ delegate :load_cache, to: :cache
6
+ delegate :find_and_add_template, to: :partialer
4
7
 
5
8
  def initialize(base, defered = [], fragments = [])
6
9
  @base = base
@@ -16,22 +19,6 @@ module Props
16
19
  @deferment.disable!
17
20
  end
18
21
 
19
- def refine_options(options, item = nil)
20
- options = @partialer.refine_options(options, item)
21
- if !@deferment.disabled
22
- options = @deferment.refine_options(options, item)
23
- end
24
-
25
- Cache.refine_options(options, item)
26
- end
27
-
28
- def refine_all_item_options(all_options)
29
- return all_options if all_options.empty?
30
-
31
- all_options = @partialer.find_and_add_template(all_options)
32
- @cache.multi_fetch_and_add_results(all_options)
33
- end
34
-
35
22
  def deferred
36
23
  @deferment.deferred
37
24
  end
@@ -44,26 +31,35 @@ module Props
44
31
  options[:defer] || options[:cache] || options[:partial] || options[:key]
45
32
  end
46
33
 
47
- def handle(options)
34
+ def handle(options, item_context = nil)
48
35
  return yield if !has_extensions(options)
49
36
 
50
- if options[:defer] && !@deferment.disabled
51
- placeholder = @deferment.handle(options)
37
+ if (key = options[:key]) && item_context
38
+ val = if item_context.respond_to? key
39
+ item_context.send(key)
40
+ elsif item_context.is_a? Hash
41
+ item_context[key] || item_context[key.to_sym]
42
+ end
43
+ end
44
+
45
+ deferment_type = @deferment.extract_deferment_type(options, item_context) if !@deferment.disabled
46
+
47
+ if deferment_type
48
+ placeholder = @deferment.handle(options, deferment_type, key, val)
52
49
  base.stream.push_value(placeholder)
53
- @fragment.handle(options)
50
+ @fragment.handle(options, item_context)
54
51
  else
55
- handle_cache(options) do
52
+ handle_cache(options, item_context) do
56
53
  base.set_content! do
57
54
  if options[:partial]
58
- @fragment.handle(options)
59
- @partialer.handle(options)
55
+ @fragment.handle(options, item_context)
56
+ @partialer.handle(options, item_context)
60
57
  else
61
58
  yield
62
59
  end
63
60
 
64
- if options[:key]
65
- id, val = options[:key]
66
- base.set!(id, val)
61
+ if key && val
62
+ base.set!(key, val)
67
63
  end
68
64
  end
69
65
  end
@@ -72,11 +68,13 @@ module Props
72
68
 
73
69
  private
74
70
 
75
- def handle_cache(options)
71
+ def handle_cache(options, item)
76
72
  if options[:cache]
77
73
  recently_cached = false
78
74
 
79
- state = @cache.cache(*options[:cache]) do
75
+ key, rest = Cache
76
+ .normalize_options(options[:cache], item)
77
+ state = @cache.cache(key, rest) do
80
78
  recently_cached = true
81
79
  result = nil
82
80
  start = base.stream.to_s.length
@@ -93,7 +91,7 @@ module Props
93
91
  result
94
92
  end
95
93
 
96
- meta, raw_json = state.split("\n")
94
+ meta, raw_json = state.split("\n", 2)
97
95
  next_deferred, next_fragments = Oj.load(meta)
98
96
  deferred.push(*next_deferred)
99
97
  fragments.push(*next_fragments)
@@ -2,23 +2,22 @@ module Props
2
2
  class Cache
3
3
  delegate :controller, :safe_concat, to: :@context
4
4
 
5
- def self.refine_options(options, item = nil)
6
- return options if !options[:cache]
5
+ attr_reader :results
7
6
 
8
- pass_opts = options.clone
9
- key, rest = [*options[:cache]]
7
+ def initialize(context)
8
+ @context = context
9
+ @results = {}
10
+ end
11
+
12
+ def self.normalize_options(options, item = nil)
13
+ key, rest = [*options]
10
14
  rest ||= {}
11
15
 
12
16
  if item && ::Proc === key
13
17
  key = key.call(item)
14
18
  end
15
19
 
16
- pass_opts[:cache] = [key, rest]
17
- pass_opts
18
- end
19
-
20
- def initialize(context)
21
- @context = context
20
+ [key, rest]
22
21
  end
23
22
 
24
23
  attr_reader :context
@@ -48,36 +47,21 @@ module Props
48
47
 
49
48
  keys.each do |k|
50
49
  ckey = key_to_ckey[k]
51
- result[k] = read_caches[ckey]
50
+
51
+ if read_caches[ckey]
52
+ result[k] = read_caches[ckey]
53
+ end
52
54
  end
53
55
 
54
56
  result
55
57
  end
56
58
 
57
- def multi_fetch_and_add_results(all_options)
58
- first_opts = all_options[0]
59
-
60
- if first_opts[:cache] && controller.perform_caching
61
- keys = all_options.map { |i| i[:cache][0] }
62
- c_opts = first_opts[:cache][1]
63
- result = multi_fetch(keys, c_opts)
64
-
65
- all_options.map do |opts|
66
- key = opts[:cache][0]
67
-
68
- if result.key? key
69
- opts[:cache][1][:result] = result[key]
70
- end
71
-
72
- opts
73
- end
74
- else
75
- all_options
76
- end
59
+ def load_cache(keys, options = {})
60
+ @results = results.merge multi_fetch(keys, options)
77
61
  end
78
62
 
79
- # Copied from jbuilder
80
- #
63
+ # The below was copied from the wonderful jbuilder library Its also MIT
64
+ # licensed, so no issues there. Thanks to the jbuilder authors!
81
65
 
82
66
  def cache(key = nil, options = {})
83
67
  if controller.perform_caching
@@ -90,10 +74,9 @@ module Props
90
74
  end
91
75
 
92
76
  def cache_fragment_for(key, options, &block)
93
- key = cache_key(key, options)
94
-
95
- return options[:result] if options[:result]
77
+ return results[key] if results[key]
96
78
 
79
+ key = cache_key(key, options)
97
80
  read_fragment_cache(key, options) || write_fragment_cache(key, options, &block)
98
81
  end
99
82
 
@@ -13,37 +13,27 @@ module Props
13
13
  end
14
14
 
15
15
  def refine_options(options, item = nil)
16
- return options if !options[:defer]
17
- pass_opts = options.clone
18
-
19
- type, rest = [*options[:defer]]
20
- rest ||= {
21
- placeholder: {}
22
- }
23
-
24
- if item
25
- type = (Proc === type) ? type.call(item) : type
26
- end
27
-
28
- if type
29
- pass_opts[:defer] = [type, rest]
30
- else
31
- pass_opts.delete(:defer)
32
- end
16
+ options.clone
17
+ end
33
18
 
34
- pass_opts
19
+ def extract_deferment_type(options, item)
20
+ type, _ = [*options[:defer]]
21
+ (Proc === type) ? type.call(item) : type
35
22
  end
36
23
 
37
- def handle(options)
24
+ def handle(options, type, key, val)
38
25
  return if !options[:defer]
39
26
 
40
- type, rest = options[:defer]
27
+ _, rest = [*options[:defer]]
28
+ rest ||= {
29
+ placeholder: {}
30
+ }
31
+
41
32
  placeholder = rest[:placeholder]
42
33
  success_action = rest[:success_action]
43
34
  fail_action = rest[:fail_action]
44
35
 
45
- if type.to_sym == :auto && options[:key]
46
- key, val = options[:key]
36
+ if type.to_sym == :auto && key && val
47
37
  placeholder = {}
48
38
  placeholder[key] = val
49
39
  end
@@ -7,7 +7,7 @@ module Props
7
7
  @fragments = fragments
8
8
  end
9
9
 
10
- def self.fragment_name_from_options(options)
10
+ def self.fragment_name_from_options(options, item = nil)
11
11
  return if !options[:partial]
12
12
 
13
13
  _, partial_opts = [*options[:partial]]
@@ -15,13 +15,17 @@ module Props
15
15
 
16
16
  fragment = partial_opts[:fragment]
17
17
 
18
+ if item && ::Proc === fragment
19
+ fragment = fragment.call(item)
20
+ end
21
+
18
22
  if String === fragment || Symbol === fragment
19
23
  fragment.to_s
20
24
  end
21
25
  end
22
26
 
23
- def handle(options)
24
- fragment_name = self.class.fragment_name_from_options(options)
27
+ def handle(options, item_context = nil)
28
+ fragment_name = self.class.fragment_name_from_options(options, item_context)
25
29
  path = @base.traveled_path
26
30
  .map { |item| item.is_a?(Array) ? item[0] : item }
27
31
  .join(".")
@@ -45,22 +45,6 @@ module Props
45
45
  end
46
46
  end
47
47
 
48
- def find_and_add_template(all_options)
49
- first_opts = all_options[0]
50
-
51
- if first_opts[:partial]
52
- partial_opts = block_opts_to_render_opts(@builder, first_opts)
53
- template = find_template(partial_opts)
54
-
55
- all_options.map do |opts|
56
- opts[:_template] = template
57
- opts
58
- end
59
- else
60
- all_options
61
- end
62
- end
63
-
64
48
  def find_template(partial_opts)
65
49
  partial = partial_opts[:partial]
66
50
  template_keys = retrieve_template_keys(partial_opts)
@@ -78,7 +62,7 @@ module Props
78
62
 
79
63
  def block_opts_to_render_opts(builder, options)
80
64
  partial, pass_opts = [*options[:partial]]
81
- pass_opts ||= {}
65
+ pass_opts = pass_opts&.clone || {}
82
66
  pass_opts[:locals] ||= {}
83
67
  pass_opts[:partial] = partial
84
68
  pass_opts[:formats] = [:json]
@@ -91,9 +75,17 @@ module Props
91
75
  pass_opts
92
76
  end
93
77
 
94
- def handle(options)
95
- partial_opts = block_opts_to_render_opts(@builder, options)
96
- template = options[:_template] || find_template(partial_opts)
78
+ def handle(options, item = nil)
79
+ return options if !options[:partial]
80
+
81
+ normalized_options = normalize_options(options, item)
82
+ partial_opts = block_opts_to_render_opts(@builder, normalized_options)
83
+ template = if options[:_template]
84
+ options[:_template]
85
+ else
86
+ # mutate the original options to bypass find_template a second time.
87
+ options[:_template] = find_template(partial_opts)
88
+ end
97
89
 
98
90
  render_partial(template, @context, partial_opts)
99
91
  end
@@ -133,8 +125,10 @@ module Props
133
125
  end
134
126
 
135
127
  def refine_options(options, item = nil)
136
- return options if !options[:partial]
128
+ options.clone
129
+ end
137
130
 
131
+ def normalize_options(options, item = nil)
138
132
  partial, rest = [*options[:partial]]
139
133
  rest = (rest || {}).clone
140
134
  locals = (rest[:locals] || {}).clone
@@ -150,20 +144,9 @@ module Props
150
144
  raise_invalid_option_as(as) unless /\A[a-z_]\w*\z/.match?(as.to_s)
151
145
 
152
146
  locals[as] = item
153
-
154
- if (fragment_name = rest[:fragment])
155
- if item && ::Proc === fragment_name
156
- fragment_name = fragment_name.call(item)
157
- end
158
-
159
- rest[:fragment] = fragment_name.to_s
160
- end
161
147
  end
162
148
 
163
- pass_opts = options.clone
164
- pass_opts[:partial] = [partial, rest]
165
-
166
- pass_opts
149
+ {partial: [partial, rest]}
167
150
  end
168
151
  end
169
152
  end
@@ -12,6 +12,7 @@ module Props
12
12
  @traveled_path = []
13
13
  @partialer = Partialer.new(self, context, builder)
14
14
  @fragment_name = nil
15
+ @found_item = nil
15
16
  end
16
17
 
17
18
  def deferred!
@@ -30,7 +31,7 @@ module Props
30
31
  pass_opts[:path_suffix] = traveled_path
31
32
  end
32
33
 
33
- fragment_name = Fragment.fragment_name_from_options(pass_opts)
34
+ fragment_name = Fragment.fragment_name_from_options(pass_opts, @found_item)
34
35
  if fragment_name
35
36
  @fragment_name = fragment_name
36
37
  @fragment_path = @traveled_path.clone
@@ -38,7 +39,7 @@ module Props
38
39
 
39
40
  fragment_context = @fragment_name
40
41
 
41
- [@found_block, @traveled_path, pass_opts, @fragment_path, fragment_context]
42
+ [@found_block, @traveled_path, pass_opts, @fragment_path, fragment_context, @found_item]
42
43
  end
43
44
 
44
45
  def set_content!(*args)
@@ -97,21 +98,11 @@ module Props
97
98
 
98
99
  if item
99
100
  pass_opts = @partialer.refine_options(options, item)
100
-
101
- if (key = pass_opts[:key])
102
- val = if item.respond_to? key
103
- item.send(key)
104
- elsif item.is_a? Hash
105
- item[key] || item[key.to_sym]
106
- end
107
-
108
- pass_opts[:key] = [pass_opts[:key], val]
109
- end
110
-
111
101
  @traveled_path.push(key_index)
112
102
 
113
103
  if @depth == @search_path.size - 1
114
104
  @found_options = pass_opts
105
+ @found_item = item
115
106
  @found_block = proc {
116
107
  yield item, 0
117
108
  }
@@ -120,7 +111,7 @@ module Props
120
111
 
121
112
  @depth += 1
122
113
  if pass_opts[:partial]
123
- fragment_name = Fragment.fragment_name_from_options(pass_opts)
114
+ fragment_name = Fragment.fragment_name_from_options(pass_opts, item)
124
115
  if fragment_name
125
116
  @fragment_name = fragment_name
126
117
  @fragment_path = @traveled_path.clone
@@ -0,0 +1,28 @@
1
+ array
2
+ handle_collection
3
+ all_opts = collection.map do |item|
4
+ refine_item_options(item, options)
5
+ end
6
+ creates clone of the opts using
7
+ refine_item_options clones original options
8
+ then subsequently the ext refine_item_options
9
+ gets called first,
10
+
11
+ refine_all_item_options <- operates on the entire collection
12
+
13
+ handle_collection_item
14
+ set_content options
15
+
16
+
17
+
18
+ base with ExtensionManager
19
+ refine_all_item_options - overrided with ext manager
20
+ - which attahes a _template with partialer
21
+ to it AND multifetch and attaches it to cache
22
+ as [key, result]
23
+
24
+ refine_item_options
25
+ - transforms key: :id to key = [key, val]
26
+ - passes to refine_options
27
+ which is then asks the searcher the cache and
28
+ deferment to mutate the option
@@ -1,3 +1,3 @@
1
1
  module Props
2
- VERSION = "1.0.0.alpha.4".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
@@ -53,13 +53,14 @@ module Props
53
53
  options.delete(:dig)
54
54
 
55
55
  @builder.set!(key, options, &block)
56
- found_block, found_path, found_options, fragment_path, fragment_context = @builder.found!
56
+ found_block, found_path, found_options, fragment_path, fragment_context, found_item = @builder.found!
57
57
  @found_path = found_path || []
58
58
  @fragment_context = fragment_context
59
59
  @builder = prev_builder
60
60
  @fragment_path = fragment_path
61
61
 
62
62
  if found_block
63
+ @builder.item_context = found_item
63
64
  set!(key, found_options, &found_block)
64
65
  end
65
66
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: props_template
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johny Ho
@@ -89,6 +89,7 @@ files:
89
89
  - lib/props_template/partial_patch.rb
90
90
  - lib/props_template/railtie.rb
91
91
  - lib/props_template/searcher.rb
92
+ - lib/props_template/test.md
92
93
  - lib/props_template/version.rb
93
94
  homepage: https://github.com/thoughtbot/props_template/
94
95
  licenses:
@@ -101,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
102
  requirements:
102
103
  - - ">="
103
104
  - !ruby/object:Gem::Version
104
- version: '2.5'
105
+ version: '3.3'
105
106
  required_rubygems_version: !ruby/object:Gem::Requirement
106
107
  requirements:
107
108
  - - ">="