shaf 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/shaf/app.rb +27 -9
- data/lib/shaf/command/base.rb +4 -0
- data/lib/shaf/command/new.rb +5 -1
- data/lib/shaf/command/server.rb +5 -1
- data/lib/shaf/command/templates/config/settings.yml.erb +9 -8
- data/lib/shaf/extensions/resource_uris.rb +37 -155
- data/lib/shaf/extensions/symbolic_routes.rb +5 -18
- data/lib/shaf/formable/builder.rb +58 -19
- data/lib/shaf/formable/form.rb +13 -10
- data/lib/shaf/formable.rb +10 -23
- data/lib/shaf/generator/base.rb +82 -0
- data/lib/shaf/generator/controller.rb +19 -35
- data/lib/shaf/generator/forms.rb +10 -14
- data/lib/shaf/generator/migration/add_column.rb +0 -4
- data/lib/shaf/generator/migration/add_index.rb +0 -4
- data/lib/shaf/generator/migration/base.rb +8 -0
- data/lib/shaf/generator/migration/create_table.rb +0 -4
- data/lib/shaf/generator/migration/drop_column.rb +0 -4
- data/lib/shaf/generator/migration/rename_column.rb +0 -4
- data/lib/shaf/generator/model.rb +29 -14
- data/lib/shaf/generator/policy.rb +8 -14
- data/lib/shaf/generator/profile.rb +9 -14
- data/lib/shaf/generator/scaffold.rb +6 -9
- data/lib/shaf/generator/serializer.rb +31 -30
- data/lib/shaf/generator/templates/api/controller.rb.erb +13 -13
- data/lib/shaf/generator/templates/api/forms.rb.erb +2 -2
- data/lib/shaf/generator/templates/api/model.rb.erb +1 -1
- data/lib/shaf/generator/templates/api/profile.rb.erb +1 -1
- data/lib/shaf/generator/templates/api/serializer.rb.erb +1 -1
- data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +14 -14
- data/lib/shaf/helpers/paginate.rb +1 -1
- data/lib/shaf/profile.rb +8 -8
- data/lib/shaf/registrable_factory.rb +62 -32
- data/lib/shaf/responder/problem_json.rb +1 -1
- data/lib/shaf/router.rb +65 -12
- data/lib/shaf/spec/integration_spec.rb +1 -1
- data/lib/shaf/tasks.rb +0 -1
- data/lib/shaf/upgrade/package.rb +5 -7
- data/lib/shaf/version.rb +1 -1
- data/templates/Rakefile +0 -6
- data/templates/api/controllers/base_controller.rb +0 -2
- data/templates/api/serializers/root_serializer.rb +0 -11
- data/templates/config/initializers/middleware.rb +6 -0
- data/templates/spec/spec_helper.rb +4 -1
- data/upgrades/3.0.0.tar.gz +0 -0
- data.tar.gz.sig +0 -0
- metadata +19 -22
- metadata.gz.sig +0 -0
- data/lib/shaf/api_doc/comment.rb +0 -27
- data/lib/shaf/api_doc/document.rb +0 -137
- data/lib/shaf/api_doc/link_relations.rb +0 -77
- data/lib/shaf/middleware.rb +0 -1
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa31b5bc9a9cc80cc5b34c5a3f6101eb17ebf8166bd1a6ae46f0008709c3fa0f
|
4
|
+
data.tar.gz: d4fc21aa271c30bb3e52bbc65571917beb0b16029e7ee764fc8705a5d4197ca8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6820ebc741c7392a44a767d1be674394fb307c3e937997c0428dea3663fd57faa3ab9ff6700dedda76e522650373997413b4a5b256198d9646c4741a91ae33d7
|
7
|
+
data.tar.gz: 9315cdd74263a2ae7b39f8a5960267aff7b61c498e0d95ca00559f61a3756f53f84f62b946bb24d8d818d901133cc537ef4402a0b3e201ae34f52b201015f72c
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/shaf/app.rb
CHANGED
@@ -1,25 +1,43 @@
|
|
1
|
-
require '
|
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
|
-
|
8
|
+
instance.run!
|
9
9
|
end
|
10
10
|
|
11
11
|
# Or `run Shaf::App` (in config.ru)
|
12
12
|
def call(*args)
|
13
|
-
|
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
|
-
|
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
|
data/lib/shaf/command/base.rb
CHANGED
data/lib/shaf/command/new.rb
CHANGED
@@ -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,
|
55
|
+
erb(content, locals)
|
52
56
|
end
|
53
57
|
|
54
58
|
def erb(content, locals = {})
|
data/lib/shaf/command/server.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
10
|
+
migrations_dir: db/migrations
|
11
|
+
paginate_per_page: 25
|
12
|
+
port: <%= default_port %>
|
13
|
+
project_name: <%= project_name %>
|
14
14
|
protocol: http
|
15
|
-
|
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,
|
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
|
-
|
120
|
-
|
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, :
|
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
|
-
|
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(
|
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_#{
|
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_#{
|
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
|
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
|
-
|
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
|
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
|
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
|
414
|
-
[
|
415
|
-
|
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
|
-
|
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
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
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
|
-
|
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
|
-
|
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,
|
12
|
+
def rewrite_path(path, method)
|
14
13
|
return path unless path.is_a? Symbol
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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 :
|
65
|
+
attr_reader :current
|
25
66
|
|
26
|
-
def exec_with_form(block,
|
27
|
-
|
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
|
-
@
|
71
|
+
@current = prev
|
32
72
|
end
|
33
73
|
|
34
|
-
def new_form
|
35
|
-
(form
|
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
|
-
|
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
|
-
|
84
|
+
current.send(:"#{name}=", arg)
|
46
85
|
end
|
47
86
|
end
|
48
87
|
|
49
88
|
def field(name, opts = {})
|
50
|
-
|
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,
|
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
|
data/lib/shaf/formable/form.rb
CHANGED
@@ -12,14 +12,15 @@ module Shaf
|
|
12
12
|
DEFAULT_SUBMIT = 'save'.freeze
|
13
13
|
|
14
14
|
attr_accessor :resource
|
15
|
-
|
16
|
-
|
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]
|
22
|
-
@method = params[:method]
|
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
|
-
|
36
|
-
|
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
|
44
|
-
@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)
|