shaf 2.1.0 → 3.0.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/shaf/app.rb +27 -9
  4. data/lib/shaf/command/base.rb +4 -0
  5. data/lib/shaf/command/new.rb +5 -1
  6. data/lib/shaf/command/server.rb +5 -1
  7. data/lib/shaf/command/templates/config/settings.yml.erb +9 -8
  8. data/lib/shaf/extensions/resource_uris.rb +37 -155
  9. data/lib/shaf/extensions/symbolic_routes.rb +5 -18
  10. data/lib/shaf/formable/builder.rb +58 -19
  11. data/lib/shaf/formable/form.rb +13 -10
  12. data/lib/shaf/formable.rb +10 -23
  13. data/lib/shaf/generator/base.rb +82 -0
  14. data/lib/shaf/generator/controller.rb +19 -35
  15. data/lib/shaf/generator/forms.rb +10 -14
  16. data/lib/shaf/generator/migration/add_column.rb +0 -4
  17. data/lib/shaf/generator/migration/add_index.rb +0 -4
  18. data/lib/shaf/generator/migration/base.rb +8 -0
  19. data/lib/shaf/generator/migration/create_table.rb +0 -4
  20. data/lib/shaf/generator/migration/drop_column.rb +0 -4
  21. data/lib/shaf/generator/migration/rename_column.rb +0 -4
  22. data/lib/shaf/generator/model.rb +29 -14
  23. data/lib/shaf/generator/policy.rb +8 -14
  24. data/lib/shaf/generator/profile.rb +9 -14
  25. data/lib/shaf/generator/scaffold.rb +6 -9
  26. data/lib/shaf/generator/serializer.rb +31 -30
  27. data/lib/shaf/generator/templates/api/controller.rb.erb +13 -13
  28. data/lib/shaf/generator/templates/api/forms.rb.erb +2 -2
  29. data/lib/shaf/generator/templates/api/model.rb.erb +1 -1
  30. data/lib/shaf/generator/templates/api/profile.rb.erb +1 -1
  31. data/lib/shaf/generator/templates/api/serializer.rb.erb +1 -1
  32. data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +14 -14
  33. data/lib/shaf/helpers/paginate.rb +1 -1
  34. data/lib/shaf/link_relations.rb +77 -0
  35. data/lib/shaf/profile.rb +8 -8
  36. data/lib/shaf/registrable_factory.rb +62 -32
  37. data/lib/shaf/responder/problem_json.rb +1 -1
  38. data/lib/shaf/router.rb +65 -12
  39. data/lib/shaf/spec/integration_spec.rb +1 -1
  40. data/lib/shaf/tasks.rb +0 -1
  41. data/lib/shaf/upgrade/package.rb +5 -7
  42. data/lib/shaf/utils.rb +2 -2
  43. data/lib/shaf/version.rb +1 -1
  44. data/lib/shaf/yard/link_object.rb +2 -3
  45. data/templates/Rakefile +0 -6
  46. data/templates/api/controllers/base_controller.rb +0 -2
  47. data/templates/api/serializers/root_serializer.rb +0 -11
  48. data/templates/config/initializers/middleware.rb +6 -0
  49. data/templates/spec/spec_helper.rb +4 -1
  50. data/upgrades/3.0.0.tar.gz +0 -0
  51. data/yard_templates/api_doc/profile_attribute/html/attribute.erb +2 -1
  52. data/yard_templates/api_doc/resource_attribute/html/attribute.erb +2 -1
  53. data/yard_templates/api_doc/sidebar/html/profile_list.erb +2 -1
  54. data/yard_templates/api_doc/sidebar/html/serializer_list.erb +2 -1
  55. data.tar.gz.sig +0 -0
  56. metadata +34 -36
  57. metadata.gz.sig +0 -0
  58. data/lib/shaf/api_doc/comment.rb +0 -27
  59. data/lib/shaf/api_doc/document.rb +0 -137
  60. data/lib/shaf/api_doc/link_relations.rb +0 -77
  61. data/lib/shaf/middleware.rb +0 -1
  62. data/lib/shaf/tasks/api_doc_task.rb +0 -146
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dc76b4b8ddbc8c627a2f03eb3f3f889771a21cc950de357fc6d3d50a7ba3008
4
- data.tar.gz: 5c6ab688fa85a69650e6741933b9ddbad4dd6d40693ce0998d9fb88b14e212ef
3
+ metadata.gz: c508aa7154d738ed2009c18256326f590917af8c24d60bfacfd5bb91613c4270
4
+ data.tar.gz: 49e9fec1c522764bb1a722623cfb49cf8de3d6d7e026355a09310a6099828711
5
5
  SHA512:
6
- metadata.gz: 154deb196fe2f4583599024524bd21b06fadc039fb99971ed2360acffb65b1339c79c8b61edebbf230df558473ef9f11cc0baa54c79b52df0989c60d60e7debf
7
- data.tar.gz: 49d240389e58f852e4445ccd321f83bb501d803bb957c328816d470ac5bb64c648e293be26b5dbda07e57649fe1987b339e4dc458e4d5f27c3b56e120f14adbe
6
+ metadata.gz: d1d2ddda76cb3e76470f4cbc0297e72ef3c3b9c6119a12d101d999a50bc0aab37a442067ddd0cb4fdd3e698d0446982e65d199e633e46d875175e087f3bc9a61
7
+ data.tar.gz: 3d2c97ed1362ac58addf9c282e37d8754adad5a994c421d72779e4576dd91c8cbd1bbfc67689d20bf51bc20410270f61752383d36b11eb9dcbe28883c6552440
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/shaf/app.rb CHANGED
@@ -1,25 +1,43 @@
1
- require 'shaf/middleware'
1
+ require 'sinatra'
2
2
 
3
3
  module Shaf
4
4
  class App
5
5
  class << self
6
6
  # Either call `Shaf::App.run!`
7
7
  def run!
8
- app.run!
8
+ instance.run!
9
9
  end
10
10
 
11
11
  # Or `run Shaf::App` (in config.ru)
12
12
  def call(*args)
13
- app.call(*args)
13
+ instance.call(*args)
14
14
  end
15
15
 
16
+ def instance
17
+ # This works since Sinatra includes Sinatra::Delegator into
18
+ # Rack::Builder, which means that Rack::Builder#set will be delegated
19
+ # to Sinatra::Application
20
+ @instance ||= Rack::Builder.new(app) do
21
+ set :port, Settings.port || 3000
22
+ end
23
+ end
24
+
25
+ def use(middleware, *args, **kwargs, &block)
26
+ if args.empty? && kwargs.empty?
27
+ instance.use middleware, &block
28
+ elsif kwargs.empty?
29
+ instance.use middleware, *args, &block
30
+ elsif args.empty?
31
+ instance.use middleware, **kwargs, &block
32
+ else
33
+ instance.use middleware, *args, **kwargs, &block
34
+ end
35
+ end
36
+
37
+ private
38
+
16
39
  def app
17
- @app ||=
18
- Sinatra.new.tap do |app|
19
- app.set :port, Settings.port || 3000
20
- app.use Middleware::RequestId
21
- app.use Router
22
- end
40
+ Router.new
23
41
  end
24
42
  end
25
43
  end
@@ -23,6 +23,10 @@ module Shaf
23
23
  @usage = str || block
24
24
  end
25
25
 
26
+ def identified_by
27
+ @identifiers
28
+ end
29
+
26
30
  def exit_with_error(msg, status)
27
31
  STDERR.puts msg
28
32
  exit status
@@ -47,8 +47,12 @@ module Shaf
47
47
  settings_file = 'config/settings.yml'
48
48
  template_file = File.expand_path("../templates/#{settings_file}.erb", __FILE__)
49
49
  content = File.read(template_file)
50
+ locals = {
51
+ project_name: project_name.capitalize,
52
+ default_port: "<%= ENV.fetch('PORT', 3000) %>"
53
+ }
50
54
  File.write settings_file,
51
- erb(content, project_name: project_name.capitalize)
55
+ erb(content, locals)
52
56
  end
53
57
 
54
58
  def erb(content, locals = {})
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'rack'
2
3
 
3
4
  module Shaf
4
5
  module Command
@@ -16,7 +17,10 @@ module Shaf
16
17
  def call
17
18
  Settings.port = options[:port] if options[:port]
18
19
  bootstrap
19
- App.run!
20
+ Rack::Server.start(
21
+ app: App,
22
+ Port: Settings.port
23
+ )
20
24
  end
21
25
  end
22
26
  end
@@ -1,23 +1,24 @@
1
1
  ---
2
2
  default: &default
3
- project_name: <%= project_name %>
4
- public_folder: frontend/assets
5
- views_folder: frontend/views
3
+ default_authentication_realm: api
6
4
  documents_dir: doc/api
7
- migrations_dir: db/migrations
8
5
  fixtures_dir: spec/fixtures
9
- paginate_per_page: 25
6
+ hostname: localhost
10
7
  http_cache: on
11
8
  http_cache_max_age_long: 86400 # 60 * 60 * 24 = 1 day
12
9
  http_cache_max_age_short: 3600 # 60 * 60 = 1 hour
13
- hostname: localhost
10
+ migrations_dir: db/migrations
11
+ paginate_per_page: 25
12
+ port: <%= default_port %>
13
+ project_name: <%= project_name %>
14
14
  protocol: http
15
- port: 3000
15
+ public_folder: frontend/assets
16
+ views_folder: frontend/views
16
17
 
17
18
  production:
18
19
  <<: *default
19
- port: <%= ENV.fetch('PORT', 443) %>
20
20
  base_uri: https://my.public.shaf.api.com
21
+ port: <%= ENV.fetch('PORT', 443) %>
21
22
 
22
23
  development:
23
24
  <<: *default
@@ -106,26 +106,20 @@ module Shaf
106
106
  # edit_book_uri_template => /books/:id/edit
107
107
  #
108
108
  class CreateUriMethods
109
- def initialize(name, base: nil, plural_name: nil, only: nil, except: nil)
109
+ def initialize(name, plural_name: nil, base: nil, namespace: nil, only: nil, except: nil)
110
110
  @name = name.to_s
111
- @base = base&.sub(%r(/\Z), '') || ''
112
111
  @plural_name = plural_name&.to_s || Utils::pluralize(name.to_s)
112
+ @base = base&.sub(%r(/\Z), '') || ''
113
+ @base = "/#{namespace}" if namespace && !base
114
+ @namespace = namespace
113
115
  @only = only
114
116
  @except = except
115
117
  @added_path_methods = []
116
118
  end
117
119
 
118
120
  def call
119
- if plural_name == name
120
- # Deprecated code path
121
- # Remove this branch and only keep the `else` behavior when dropping
122
- # support for this
123
- register_resource_helper_by_arg
124
- else
125
- register_collection_helper
126
- register_resource_helper
127
- end
128
-
121
+ register_collection_helper
122
+ register_resource_helper
129
123
  register_new_resource_helper
130
124
  register_edit_resource_helper
131
125
  @added_path_methods
@@ -133,51 +127,38 @@ module Shaf
133
127
 
134
128
  private
135
129
 
136
- attr_reader :name, :base, :plural_name, :only, :except
130
+ attr_reader :name, :plural_name, :base, :namespace, :only, :except
137
131
 
138
132
  def register_collection_helper
139
133
  return if skip? :collection
140
134
 
135
+ method = method_name(plural_name, name == plural_name)
141
136
  template_uri = "#{base}/#{plural_name}".freeze
142
- method_name = plural_name
143
- method_name = "#{name}_collection" if name == @plural_name
144
- register(method_name, template_uri)
137
+ register(method, template_uri)
145
138
  end
146
139
 
147
140
  def register_resource_helper
148
141
  return if skip? :resource
149
142
 
143
+ method = method_name(name)
150
144
  template_uri = "#{base}/#{plural_name}/:id".freeze
151
- register(name, template_uri)
152
- end
153
-
154
- # If a resource has the same singular and plural names, then this method
155
- # should be used. It will return the resource uri when a resource is given
156
- # as argument and the resources uri when no arguments are provided.
157
- def register_resource_helper_by_arg
158
- return register_resource_helper if skip? :collection
159
- register_collection_helper
160
- return if skip? :new
161
-
162
- resource_template_uri = "#{base}/#{plural_name}/:id"
163
- collection_template_uri = "#{base}/#{plural_name}"
164
-
165
- builder = MethodBuilder.new(name, resource_template_uri, alt_uri: collection_template_uri)
166
- @added_path_methods << builder.call
145
+ register(method, template_uri)
167
146
  end
168
147
 
169
148
  def register_new_resource_helper
170
149
  return if skip? :new
171
150
 
151
+ method = method_name(name)
172
152
  template_uri = "#{base}/#{name}/form".freeze
173
- register("new_#{name}", template_uri)
153
+ register("new_#{method}", template_uri)
174
154
  end
175
155
 
176
156
  def register_edit_resource_helper
177
157
  return if skip? :edit
178
158
 
159
+ method = method_name(name)
179
160
  template_uri = "#{base}/#{plural_name}/:id/edit".freeze
180
- register("edit_#{name}", template_uri)
161
+ register("edit_#{method}", template_uri)
181
162
  end
182
163
 
183
164
  def register(name, template_uri)
@@ -194,11 +175,14 @@ module Shaf
194
175
  false
195
176
  end
196
177
  end
178
+
179
+ def method_name(name, collection = false)
180
+ collection_str = "collection" if collection
181
+ [namespace, name, collection_str].compact.join('_')
182
+ end
197
183
  end
198
184
 
199
185
  class MethodBuilder
200
- NO_GIVEN_VALUE = Object.new
201
-
202
186
  def self.query_string(query)
203
187
  return '' unless query&.any?
204
188
 
@@ -211,10 +195,9 @@ module Shaf
211
195
  [query_str, fragment_str].join
212
196
  end
213
197
 
214
- def initialize(name, uri, alt_uri: nil)
198
+ def initialize(name, uri)
215
199
  @name = name
216
200
  @uri = uri.dup.freeze
217
- @alt_uri = alt_uri.dup.freeze
218
201
  end
219
202
 
220
203
  def call
@@ -223,16 +206,12 @@ module Shaf
223
206
  raise exception.new(name, uri_method_name)
224
207
  end
225
208
 
226
- if alt_uri.nil?
227
- build_methods
228
- else
229
- build_methods_with_optional_arg
230
- end
209
+ build_methods
231
210
  end
232
211
 
233
212
  private
234
213
 
235
- attr_reader :name, :uri, :alt_uri
214
+ attr_reader :name, :uri
236
215
 
237
216
  def build_methods
238
217
  UriHelperMethods.eval_method uri_method_string
@@ -243,15 +222,6 @@ module Shaf
243
222
  path_method_name.to_sym
244
223
  end
245
224
 
246
- def build_methods_with_optional_arg
247
- UriHelperMethods.eval_method uri_method_with_optional_arg_string
248
- UriHelperMethods.eval_method path_method_with_optional_arg_string
249
- UriHelperMethods.register(template_method_name, &template_proc)
250
- UriHelperMethods.register(legacy_template_method_name, &template_proc)
251
- UriHelperMethods.register(path_matcher_name, &path_matcher_proc)
252
- path_method_name.to_sym
253
- end
254
-
255
225
  def uri_method_name
256
226
  "#{name}_uri".freeze
257
227
  end
@@ -309,53 +279,6 @@ module Shaf
309
279
  RUBY
310
280
  end
311
281
 
312
- def uri_method_with_optional_arg_string
313
- base_uri = UriHelper.base_uri
314
- arg_no = extract_symbols(alt_uri).size
315
- <<~RUBY
316
- def #{uri_signature(uri: alt_uri, optional_args: 1)}
317
- query_str = Shaf::MethodBuilder.query_string(query)
318
- if arg#{arg_no}.nil?
319
- warn <<~DEPRECATION
320
-
321
- Deprecated use of collection uri helper:
322
- To get the collection uri use ##{name}_collection_uri instead of ##{uri_method_name}.
323
- Or pass an argument to ##{uri_method_name} to get the uri to a resource.
324
- \#{caller.find { |s| !s.match? %r{lib/shaf/extensions/resource_uris.rb} }}
325
-
326
- DEPRECATION
327
-
328
- \"#{base_uri}#{interpolated_uri_string(alt_uri)}\#{query_str}\".freeze
329
- else
330
- \"#{base_uri}#{interpolated_uri_string(uri)}\#{query_str}\".freeze
331
- end
332
- end
333
- RUBY
334
- end
335
-
336
- def path_method_with_optional_arg_string
337
- arg_no = extract_symbols(alt_uri).size
338
- <<~RUBY
339
- def #{path_signature(uri: alt_uri, optional_args: 1)}
340
- query_str = Shaf::MethodBuilder.query_string(query)
341
- if arg#{arg_no}.nil?
342
- warn <<~DEPRECATION
343
-
344
- Deprecated use of collection path helper:
345
- To get the collection path use ##{name}_collection_path instead of ##{path_method_name}.
346
- Or pass an argument to ##{path_method_name} to get the path to a resource.
347
- \#{caller.find { |s| !s.match? %r{lib/shaf/extensions} }}
348
-
349
- DEPRECATION
350
-
351
- \"#{interpolated_uri_string(alt_uri)}\#{query_str}\".freeze
352
- else
353
- \"#{interpolated_uri_string(uri)}\#{query_str}\".freeze
354
- end
355
- end
356
- RUBY
357
- end
358
-
359
282
  def extract_symbols(uri = @uri)
360
283
  uri.split('/').grep(/\A:.+/).map { |t| t[1..-1].to_sym }
361
284
  end
@@ -384,70 +307,29 @@ module Shaf
384
307
  end
385
308
 
386
309
  def template_proc
387
- uri, alt_uri = @uri, @alt_uri
388
-
389
- if alt_uri.nil?
390
- -> { uri }
391
- else
392
- deprecated_method = template_method_name
393
- replacing_method = "#{name}_collection_path_template"
394
-
395
- lambda do |collection = NO_GIVEN_VALUE|
396
- if collection != NO_GIVEN_VALUE
397
- warn <<~DEPRECATION
398
-
399
- Deprecated use of uri template helper with `collection` argument:
400
- Use #{replacing_method} instead of #{deprecated_method}"
401
- #{caller.find { |s| !s.match? %r{lib/shaf/extensions} }}
402
-
403
- DEPRECATION
404
- else
405
- collection = false
406
- end
407
-
408
- collection ? alt_uri : uri
409
- end
410
- end
310
+ uri = @uri
311
+ -> { uri }
411
312
  end
412
313
 
413
- def path_mather_patterns
414
- [
415
- uri.gsub(%r{:[^/]*}, '\w+'),
416
- alt_uri&.gsub(%r{:[^/]*}, '\w+')
417
- ].compact.map { |str| Regexp.new("\\A#{str}\\Z") }
314
+ def path_mather_pattern
315
+ pattern = uri.gsub(%r{:[^/]*}, '\w+')
316
+ Regexp.new("\\A#{pattern}\\Z")
418
317
  end
419
318
 
420
319
  def path_matcher_proc
421
- patterns = path_mather_patterns
422
-
423
- deprecated_method = path_matcher_name
424
- replacing_method = "#{name}_collection_path?"
425
-
426
- lambda do |path = nil, collection: NO_GIVEN_VALUE|
427
- if collection != NO_GIVEN_VALUE
428
- warn <<~DEPRECATION
429
-
430
- Deprecated use of uri predicate helper with `collection` argument:
431
- Use #{replacing_method} instead of #{deprecated_method}(collection: true)
432
- #{caller.find { |s| !s.match? %r{lib/shaf/extensions} }}
433
-
434
- DEPRECATION
435
- else
436
- collection = false
437
- end
320
+ pattern = path_mather_pattern
438
321
 
322
+ lambda do |path = nil|
439
323
  unless path
440
324
  r = request if respond_to? :request
441
- path = r.path_info if r&.respond_to? :path_info
442
-
443
- unless path
444
- raise(
445
- ArgumentError,
446
- "Uri must be given (or #{self} should respond to :request)"
447
- )
448
- end
325
+ path = r.path_info if r.respond_to? :path_info
326
+
327
+ raise(
328
+ ArgumentError,
329
+ "Uri must be given (or #{self} should respond to :request)"
330
+ ) unless path
449
331
  end
450
- pattern = collection ? patterns.last : patterns.first
332
+
451
333
  !!(pattern =~ path)
452
334
  end
453
335
  end
@@ -4,30 +4,17 @@ module Shaf
4
4
 
5
5
  Shaf::SUPPORTED_HTTP_METHODS.each do |m|
6
6
  define_method m do |path, **options, &block|
7
- collection = options.delete(:collection)
8
- path = rewrite_path(path, collection, m)
7
+ path = rewrite_path(path, m)
9
8
  super(path, **options, &block)
10
9
  end
11
10
  end
12
11
 
13
- def rewrite_path(path, collection, method)
12
+ def rewrite_path(path, method)
14
13
  return path unless path.is_a? Symbol
15
14
 
16
- warn <<~DEPRECATION unless collection.nil?
17
- Deprecated use of declaring route with collection keyword argument:
18
- Use `#{method} :#{path.to_s.sub(/_(path|uri)/, '_collection_path')} do`
19
- instead of `#{method} :#{path}, collection: #{collection} do`
20
- #{caller.find { |s| s.match?(/_controller.rb/) }}
21
-
22
- DEPRECATION
23
-
24
- method = "#{path}_template"
25
- send_args = [method]
26
- send_args << collection unless collection.nil?
27
- return send(*send_args) if respond_to? method
28
-
29
- method = "#{path}_path_template"
30
- return send(*send_args) if respond_to? method
15
+ ["#{path}_template", "#{path}_path_template"].each do |method|
16
+ return send(method) if respond_to? method
17
+ end
31
18
 
32
19
  raise UriHelperNotRegisterdError, <<~RUBY
33
20
  Undefined method '#{method}'. Did you forget to register a uri helper for #{path}?
@@ -1,11 +1,56 @@
1
+ require 'forwardable'
1
2
  require 'shaf/formable/form'
3
+ require 'shaf/immutable_attr'
2
4
 
3
5
  module Shaf
4
6
  module Formable
5
7
  class Builder
6
- InstanceAccessorType = Struct.new(:prefill?)
7
8
  DELEGATES = %i[title name action method type submit fields].freeze
8
9
 
10
+ class FormWrapper
11
+ extend Forwardable
12
+ extend Shaf::ImmutableAttr
13
+
14
+ attr_accessor :instance_accessor
15
+ immutable_reader :form
16
+
17
+ WRITER_DELEGATES = DELEGATES.map { |method| :"#{method}=" }
18
+ def_delegators :@form, :add_field, *WRITER_DELEGATES
19
+
20
+ def initialize(form, method_name: nil, instance_accessor: nil)
21
+ @form = form&.dup || Formable::Form.new
22
+ @method_name = method_name
23
+ @form.action = action_from(method_name) unless @form.action
24
+ @instance_accessor = instance_accessor
25
+ end
26
+
27
+ def action_from(method_name)
28
+ return unless method_name
29
+
30
+ (method_name.to_s.delete_suffix('_form')).to_sym
31
+ end
32
+
33
+ def method_name
34
+ name = @method_name || form.action
35
+
36
+ if name.nil?
37
+ nil
38
+ elsif name.to_s.end_with? '_form'
39
+ name.to_sym
40
+ else
41
+ :"#{name}_form"
42
+ end
43
+ end
44
+
45
+ def instance_accessor?
46
+ [:empty, :prefill].include? instance_accessor
47
+ end
48
+
49
+ def prefill?
50
+ instance_accessor == :prefill
51
+ end
52
+ end
53
+
9
54
  attr_reader :forms
10
55
 
11
56
  def initialize(&block)
@@ -15,48 +60,42 @@ module Shaf
15
60
  exec_with_form(block)
16
61
  end
17
62
 
18
- def instance_accessor_for(form)
19
- @instance_accessors[form.action]
20
- end
21
-
22
63
  private
23
64
 
24
- attr_reader :form
65
+ attr_reader :current
25
66
 
26
- def exec_with_form(block, action: nil)
27
- current, @form = form, new_form
28
- form.action = action if action
67
+ def exec_with_form(block, method_name: nil)
68
+ prev, @current = current, new_form(method_name)
29
69
  instance_exec(&block)
30
70
  ensure
31
- @form = current
71
+ @current = prev
32
72
  end
33
73
 
34
- def new_form
35
- (form&.dup || Formable::Form.new).tap { |f| @forms << f }
74
+ def new_form(method_name)
75
+ FormWrapper.new(current&.form, method_name: method_name).tap { |f| @forms << f }
36
76
  end
37
77
 
38
78
  def instance_accessor(prefill: true)
39
- acc = InstanceAccessorType.new(prefill)
40
- @instance_accessors[form.action] = acc
79
+ current.instance_accessor = prefill ? :prefill : :empty
41
80
  end
42
81
 
43
82
  DELEGATES.each do |name|
44
83
  define_method(name) do |arg|
45
- form.send(:"#{name}=", arg)
84
+ current.send(:"#{name}=", arg)
46
85
  end
47
86
  end
48
87
 
49
88
  def field(name, opts = {})
50
- form.add_field(name, opts)
89
+ current.add_field(name, opts)
51
90
  end
52
91
 
53
92
  def method_missing(method, *args, &block)
54
93
  return super unless args.empty? && block
55
- exec_with_form(block, action: method)
94
+ exec_with_form(block, method_name: method)
56
95
  end
57
96
 
58
- def respond_to_missing?(*)
59
- true
97
+ def respond_to_missing?(method, _include_private = false)
98
+ method.to_s.end_with?('_form') ? true : super
60
99
  end
61
100
  end
62
101
  end
@@ -12,14 +12,15 @@ module Shaf
12
12
  DEFAULT_SUBMIT = 'save'.freeze
13
13
 
14
14
  attr_accessor :resource
15
- immutable_accessor :title, :name, :href, :type, :submit, :self_link
16
- immutable_reader :fields, :action
15
+ attr_writer :name, :action
16
+ immutable_accessor :title, :href, :type, :submit, :self_link
17
+ immutable_reader :fields
17
18
 
18
19
  def initialize(params = {})
19
20
  @title = params[:title]
20
21
  @action = params[:action]
21
- @name = params[:name]&.to_sym || name_from(@action)
22
- @method = params[:method] ||= http_method_from(@action)
22
+ @name = params[:name]
23
+ @method = params[:method]
23
24
  @type = params[:type] || DEFAULT_TYPE
24
25
  @submit = params[:submit] || DEFAULT_SUBMIT
25
26
  @fields = (params[:fields] || {}).map do |name, args|
@@ -27,23 +28,25 @@ module Shaf
27
28
  end
28
29
  end
29
30
 
31
+ def name
32
+ (@name || name_from(action))&.to_sym
33
+ end
34
+
30
35
  def method=(http_method)
31
36
  @method = http_method.to_s.upcase
32
37
  end
33
38
 
34
39
  def method
35
- return unless @method
36
- @method.to_s.upcase
40
+ _method = @method || http_method_from(action)
41
+ _method.to_s.upcase if _method
37
42
  end
38
43
 
39
44
  def fields=(fields)
40
45
  @fields = fields.map { |name, args| Field.new(name, args) }
41
46
  end
42
47
 
43
- def action=(action)
44
- @action = action
45
- @name ||= name_from action
46
- @method ||= http_method_from action
48
+ def action
49
+ @action&.to_sym
47
50
  end
48
51
 
49
52
  def add_field(name, opts)