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.
- 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/link_relations.rb +77 -0
- 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/utils.rb +2 -2
- data/lib/shaf/version.rb +1 -1
- data/lib/shaf/yard/link_object.rb +2 -3
- 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/yard_templates/api_doc/profile_attribute/html/attribute.erb +2 -1
- data/yard_templates/api_doc/resource_attribute/html/attribute.erb +2 -1
- data/yard_templates/api_doc/sidebar/html/profile_list.erb +2 -1
- data/yard_templates/api_doc/sidebar/html/serializer_list.erb +2 -1
- data.tar.gz.sig +0 -0
- metadata +34 -36
- 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
data/lib/shaf/formable.rb
CHANGED
@@ -3,43 +3,30 @@ require 'shaf/formable/builder'
|
|
3
3
|
module Shaf
|
4
4
|
module Formable
|
5
5
|
def self.add_class_reader(clazz, name, form)
|
6
|
-
clazz.define_singleton_method(name) { form }
|
6
|
+
clazz.define_singleton_method(name) { form.dup }
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.add_instance_reader(clazz, name, form, prefill)
|
10
10
|
clazz.define_method(name) do
|
11
|
-
form.tap do |f|
|
11
|
+
form.dup.tap do |f|
|
12
12
|
f.resource = self
|
13
13
|
f.fill! if prefill
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# Deprecated legacy way of specifying forms inside models
|
19
|
-
def form(&block)
|
20
|
-
forms_for(self, &block)
|
21
|
-
|
22
|
-
Shaf.log.info <<~MSG
|
23
|
-
|
24
|
-
|
25
|
-
DEPRECATED method ::form in #{self}
|
26
|
-
Declare forms in a separate class extending Shaf::Formable with the class method forms_for!
|
27
|
-
MSG
|
28
|
-
end
|
29
|
-
|
30
|
-
# New way of writing forms in a separate class/file
|
31
18
|
def forms_for(clazz, &block)
|
32
19
|
builder = Formable::Builder.new(&block)
|
33
|
-
builder.forms.each do |
|
34
|
-
|
35
|
-
|
20
|
+
builder.forms.each do |form_wrapper|
|
21
|
+
method_name = form_wrapper.method_name
|
22
|
+
next unless method_name
|
36
23
|
|
37
|
-
|
24
|
+
form = form_wrapper.form
|
38
25
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
26
|
+
Formable.add_class_reader(clazz, method_name, form)
|
27
|
+
next unless form_wrapper.instance_accessor?
|
28
|
+
|
29
|
+
Formable.add_instance_reader(clazz, method_name, form, form_wrapper.prefill?)
|
43
30
|
end
|
44
31
|
end
|
45
32
|
alias form_for forms_for
|
data/lib/shaf/generator/base.rb
CHANGED
@@ -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 options(option_parser, options); end
|
27
31
|
end
|
28
32
|
|
@@ -33,6 +37,60 @@ module Shaf
|
|
33
37
|
|
34
38
|
def call; end
|
35
39
|
|
40
|
+
def identifier
|
41
|
+
self.class.identified_by
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def params
|
47
|
+
args[1..-1].map { |param| param.split(':')}
|
48
|
+
end
|
49
|
+
|
50
|
+
def name_arg
|
51
|
+
n = args.first || ''
|
52
|
+
return n unless n.empty?
|
53
|
+
raise Command::ArgumentError,
|
54
|
+
"Please provide a name when using the #{identifier} generator!"
|
55
|
+
end
|
56
|
+
|
57
|
+
def name
|
58
|
+
name_arg.split('/', 2).last
|
59
|
+
end
|
60
|
+
|
61
|
+
def model_class_name
|
62
|
+
Utils.model_name(name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def plural_name
|
66
|
+
Utils.pluralize(name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def resource_name
|
70
|
+
[namespace, name].compact.join('_')
|
71
|
+
end
|
72
|
+
|
73
|
+
def collection_name
|
74
|
+
[namespace, plural_name].compact.join('_')
|
75
|
+
end
|
76
|
+
|
77
|
+
def namespace
|
78
|
+
names = name_arg.split('/')
|
79
|
+
return if names.size == 1
|
80
|
+
|
81
|
+
warn "Only a single namespaces is allowed: #{name_arg}" if names.size > 2
|
82
|
+
|
83
|
+
names.first
|
84
|
+
end
|
85
|
+
|
86
|
+
def module_name
|
87
|
+
Utils.model_name(namespace) if namespace
|
88
|
+
end
|
89
|
+
|
90
|
+
def target(directory: target_dir, ns: namespace, name: target_name)
|
91
|
+
File.join(*[directory, ns, name].compact)
|
92
|
+
end
|
93
|
+
|
36
94
|
def template_dir
|
37
95
|
File.expand_path('templates', __dir__)
|
38
96
|
end
|
@@ -56,6 +114,30 @@ module Shaf
|
|
56
114
|
raise
|
57
115
|
end
|
58
116
|
|
117
|
+
def wrap_in_module(content, module_name, search: nil)
|
118
|
+
return content if module_name.nil? || module_name.empty?
|
119
|
+
|
120
|
+
indentation = ' '
|
121
|
+
search ||= '(class|module) \w'
|
122
|
+
lines = []
|
123
|
+
added = false
|
124
|
+
|
125
|
+
content.split("\n").each do |line|
|
126
|
+
unless added
|
127
|
+
if m = line.match(/\A(\s*)#{search}/)
|
128
|
+
lines << "#{m[1]}module #{module_name}"
|
129
|
+
added = true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
line.prepend(indentation) if added
|
134
|
+
lines << line
|
135
|
+
end
|
136
|
+
|
137
|
+
lines << 'end' if added
|
138
|
+
lines.join("\n")
|
139
|
+
end
|
140
|
+
|
59
141
|
def write_output(file, content)
|
60
142
|
FileTransactions::CreateFileCommand.execute(file) { content }
|
61
143
|
puts "Added: #{file}"
|
@@ -13,24 +13,7 @@ module Shaf
|
|
13
13
|
add_link_to_root
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
args[1..-1].map { |param| param.split(':')}
|
18
|
-
end
|
19
|
-
|
20
|
-
def name
|
21
|
-
n = args.first || ''
|
22
|
-
return n unless n.empty?
|
23
|
-
raise Command::ArgumentError,
|
24
|
-
'Please provide a controller name when using the controller generator!'
|
25
|
-
end
|
26
|
-
|
27
|
-
def model_class_name
|
28
|
-
Utils.model_name(name)
|
29
|
-
end
|
30
|
-
|
31
|
-
def plural_name
|
32
|
-
Utils.pluralize(name)
|
33
|
-
end
|
16
|
+
private
|
34
17
|
|
35
18
|
def pluralized_model_name
|
36
19
|
Utils.pluralize(model_class_name)
|
@@ -44,21 +27,31 @@ module Shaf
|
|
44
27
|
'spec/integration_spec.rb'
|
45
28
|
end
|
46
29
|
|
47
|
-
def
|
48
|
-
|
30
|
+
def target_dir
|
31
|
+
'api/controllers'
|
32
|
+
end
|
33
|
+
|
34
|
+
def target_name
|
35
|
+
"#{plural_name}_controller.rb"
|
49
36
|
end
|
50
37
|
|
51
38
|
def spec_target
|
52
|
-
|
39
|
+
target(directory: 'spec/integration', name: "#{plural_name}_controller_spec.rb")
|
40
|
+
end
|
41
|
+
|
42
|
+
def policy_file
|
43
|
+
File.join(['policies', namespace, "#{name}_policy"].compact)
|
53
44
|
end
|
54
45
|
|
55
46
|
def create_controller
|
56
47
|
content = render(template, opts)
|
48
|
+
content = wrap_in_module(content, module_name)
|
57
49
|
write_output(target, content)
|
58
50
|
end
|
59
51
|
|
60
52
|
def create_integration_spec
|
61
53
|
content = render(spec_template, opts)
|
54
|
+
content = wrap_in_module(content, module_name, search: "describe #{model_class_name}")
|
62
55
|
write_output(spec_target, content)
|
63
56
|
end
|
64
57
|
|
@@ -66,11 +59,14 @@ module Shaf
|
|
66
59
|
{
|
67
60
|
name: name,
|
68
61
|
plural_name: plural_name,
|
62
|
+
resource_name: resource_name,
|
63
|
+
collection_name: collection_name,
|
69
64
|
serializer_class_name: "#{model_class_name}Serializer",
|
70
65
|
model_class_name: model_class_name,
|
71
66
|
controller_class_name: "#{pluralized_model_name}Controller",
|
72
67
|
policy_class_name: "#{model_class_name}Policy",
|
73
|
-
policy_file:
|
68
|
+
policy_file: policy_file,
|
69
|
+
namespace: namespace,
|
74
70
|
params: params
|
75
71
|
}
|
76
72
|
end
|
@@ -97,19 +93,7 @@ module Shaf
|
|
97
93
|
end
|
98
94
|
|
99
95
|
def link_content(indentation = '')
|
100
|
-
|
101
|
-
|
102
|
-
# Auto generated doc:
|
103
|
-
# Link to the collection of #{plural_name}.
|
104
|
-
# Method: GET
|
105
|
-
# Example:
|
106
|
-
# ```
|
107
|
-
# curl -H "Accept: application/hal+json" \\
|
108
|
-
# -H "Authorization: abcdef" \\
|
109
|
-
# /#{plural_name}
|
110
|
-
#```
|
111
|
-
link :#{plural_name}, #{plural_name}_uri
|
112
|
-
DOC
|
96
|
+
"#{indentation}link :#{plural_name}, #{collection_name}_uri"
|
113
97
|
end
|
114
98
|
end
|
115
99
|
end
|
data/lib/shaf/generator/forms.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Shaf
|
2
4
|
module Generator
|
3
5
|
class Forms < Base
|
@@ -8,17 +10,6 @@ module Shaf
|
|
8
10
|
create_forms
|
9
11
|
end
|
10
12
|
|
11
|
-
def model_name
|
12
|
-
n = args.first || ''
|
13
|
-
return n unless n.empty?
|
14
|
-
raise Command::ArgumentError,
|
15
|
-
'Please provide a model name when using the forms generator!'
|
16
|
-
end
|
17
|
-
|
18
|
-
def model_class_name
|
19
|
-
Utils.model_name(model_name)
|
20
|
-
end
|
21
|
-
|
22
13
|
def class_name
|
23
14
|
"#{model_class_name}Forms"
|
24
15
|
end
|
@@ -27,19 +18,24 @@ module Shaf
|
|
27
18
|
'api/forms.rb'
|
28
19
|
end
|
29
20
|
|
30
|
-
def
|
31
|
-
|
21
|
+
def target_dir
|
22
|
+
'api/forms'
|
23
|
+
end
|
24
|
+
|
25
|
+
def target_name
|
26
|
+
"#{name}_forms.rb"
|
32
27
|
end
|
33
28
|
|
34
29
|
def create_forms
|
35
30
|
content = render(template, opts)
|
31
|
+
content = wrap_in_module(content, module_name)
|
36
32
|
# FIXME: Append if file exists!
|
37
33
|
write_output(target, content)
|
38
34
|
end
|
39
35
|
|
40
36
|
def opts
|
41
37
|
{
|
42
|
-
model_name:
|
38
|
+
model_name: name,
|
43
39
|
class_name: class_name,
|
44
40
|
model_class_name: model_class_name,
|
45
41
|
fields: fields
|
@@ -19,6 +19,10 @@ module Shaf
|
|
19
19
|
def usage(str = nil, &block)
|
20
20
|
@usage = str || block
|
21
21
|
end
|
22
|
+
|
23
|
+
def identified_by
|
24
|
+
@identifiers
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
def initialize(*args, **options)
|
@@ -35,6 +39,10 @@ module Shaf
|
|
35
39
|
raise Command::ArgumentError, e.message
|
36
40
|
end
|
37
41
|
|
42
|
+
def table_name
|
43
|
+
(args.first || '').tr('/', '_')
|
44
|
+
end
|
45
|
+
|
38
46
|
def add_change(change)
|
39
47
|
@changes ||= []
|
40
48
|
@changes << change if change
|
data/lib/shaf/generator/model.rb
CHANGED
@@ -5,44 +5,59 @@ module Shaf
|
|
5
5
|
identifier :model
|
6
6
|
usage 'generate model MODEL_NAME [attribute:type] [..]'
|
7
7
|
|
8
|
+
def self.options(parser, options)
|
9
|
+
parser.on("--skip-model", "don't generate model or migration") do |s|
|
10
|
+
options[:skip_model] = s
|
11
|
+
end
|
12
|
+
|
13
|
+
parser.on("--skip-migration", "don't generate a migration") do |s|
|
14
|
+
options[:skip_migration] = s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
def call
|
9
|
-
create_model
|
10
|
-
create_migration
|
19
|
+
create_model unless skip_model?
|
20
|
+
create_migration unless skip_migration?
|
11
21
|
create_serializer
|
12
22
|
create_forms
|
13
23
|
end
|
14
24
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
'Please provide a model name when using the model generator!'
|
25
|
+
private
|
26
|
+
|
27
|
+
def skip_model?
|
28
|
+
options[:skip_model]
|
20
29
|
end
|
21
30
|
|
22
|
-
def
|
23
|
-
|
31
|
+
def skip_migration?
|
32
|
+
options[:skip_migration] || skip_model?
|
24
33
|
end
|
25
34
|
|
26
35
|
def table_name
|
27
|
-
Utils.pluralize
|
36
|
+
Utils.pluralize name_arg
|
28
37
|
end
|
29
38
|
|
30
39
|
def template
|
31
40
|
'api/model.rb'
|
32
41
|
end
|
33
42
|
|
34
|
-
def
|
35
|
-
|
43
|
+
def target_dir
|
44
|
+
'api/models'
|
45
|
+
end
|
46
|
+
|
47
|
+
def target_name
|
48
|
+
"#{name}.rb"
|
36
49
|
end
|
37
50
|
|
38
51
|
def create_model
|
39
52
|
content = render(template, opts)
|
53
|
+
content = wrap_in_module(content, module_name)
|
40
54
|
write_output(target, content)
|
41
55
|
end
|
42
56
|
|
43
57
|
def opts
|
44
58
|
{
|
45
59
|
class_name: model_class_name,
|
60
|
+
table_name: [namespace, plural_name].compact.join('_')
|
46
61
|
}
|
47
62
|
end
|
48
63
|
|
@@ -52,12 +67,12 @@ module Shaf
|
|
52
67
|
end
|
53
68
|
|
54
69
|
def create_serializer
|
55
|
-
serializer_args = %W(serializer #{
|
70
|
+
serializer_args = %W(serializer #{name_arg}) + args[1..-1]
|
56
71
|
Generator::Factory.create(*serializer_args, **options).call
|
57
72
|
end
|
58
73
|
|
59
74
|
def create_forms
|
60
|
-
form_args = %W(forms #{
|
75
|
+
form_args = %W(forms #{name_arg}) + args[1..-1]
|
61
76
|
Generator::Factory.create(*form_args, **options).call
|
62
77
|
end
|
63
78
|
end
|
@@ -8,27 +8,21 @@ module Shaf
|
|
8
8
|
create_policy
|
9
9
|
end
|
10
10
|
|
11
|
-
def policy_name
|
12
|
-
n = args.first || ""
|
13
|
-
return n unless n.empty?
|
14
|
-
raise Command::ArgumentError,
|
15
|
-
"Please provide a policy name when using the policy generator!"
|
16
|
-
end
|
17
|
-
|
18
|
-
def model_class_name
|
19
|
-
Utils::model_name(policy_name)
|
20
|
-
end
|
21
|
-
|
22
11
|
def template
|
23
12
|
'api/policy.rb'
|
24
13
|
end
|
25
14
|
|
26
|
-
def
|
27
|
-
|
15
|
+
def target_dir
|
16
|
+
'api/policies'
|
17
|
+
end
|
18
|
+
|
19
|
+
def target_name
|
20
|
+
"#{name}_policy.rb"
|
28
21
|
end
|
29
22
|
|
30
23
|
def create_policy
|
31
24
|
content = render(template, opts)
|
25
|
+
content = wrap_in_module(content, module_name)
|
32
26
|
write_output(target, content)
|
33
27
|
end
|
34
28
|
|
@@ -39,7 +33,7 @@ module Shaf
|
|
39
33
|
def opts
|
40
34
|
{
|
41
35
|
policy_class_name: "#{model_class_name}Policy",
|
42
|
-
name:
|
36
|
+
name: name,
|
43
37
|
attributes: attributes,
|
44
38
|
}
|
45
39
|
end
|
@@ -8,23 +8,16 @@ module Shaf
|
|
8
8
|
create_profile
|
9
9
|
end
|
10
10
|
|
11
|
-
def profile_name
|
12
|
-
n = args.first || ""
|
13
|
-
return n unless n.empty?
|
14
|
-
raise Command::ArgumentError,
|
15
|
-
"Please provide a profile name when using the profile generator!"
|
16
|
-
end
|
17
|
-
|
18
|
-
def model_class_name
|
19
|
-
Utils::model_name(profile_name)
|
20
|
-
end
|
21
|
-
|
22
11
|
def template
|
23
12
|
'api/profile.rb'
|
24
13
|
end
|
25
14
|
|
26
|
-
def
|
27
|
-
|
15
|
+
def target_dir
|
16
|
+
'api/profiles'
|
17
|
+
end
|
18
|
+
|
19
|
+
def target_name
|
20
|
+
"#{name}.rb"
|
28
21
|
end
|
29
22
|
|
30
23
|
def attributes
|
@@ -37,14 +30,16 @@ module Shaf
|
|
37
30
|
|
38
31
|
def create_profile
|
39
32
|
content = render(template, opts)
|
33
|
+
content = wrap_in_module(content, module_name, search: 'class \w')
|
40
34
|
write_output(target, content)
|
41
35
|
end
|
42
36
|
|
43
37
|
def opts
|
44
38
|
{
|
45
|
-
profile_name:
|
39
|
+
profile_name: name,
|
46
40
|
profile_class_name: "#{model_class_name}",
|
47
41
|
attributes: attributes,
|
42
|
+
resource_name: resource_name,
|
48
43
|
}
|
49
44
|
end
|
50
45
|
end
|
@@ -6,21 +6,18 @@ module Shaf
|
|
6
6
|
usage 'generate scaffold RESOURCE_NAME [attribute:type] [..]'
|
7
7
|
|
8
8
|
def call
|
9
|
-
|
10
|
-
raise "Please provide a resource name when using the scaffold generator!"
|
11
|
-
end
|
9
|
+
check_name_arg!
|
12
10
|
|
13
11
|
options[:specs] = true if options[:specs].nil?
|
14
12
|
Generator::Factory.create('model', *args, **options).call
|
15
|
-
Generator::Factory.create('controller', *
|
13
|
+
Generator::Factory.create('controller', *args, **options).call
|
16
14
|
end
|
17
15
|
|
18
|
-
def
|
19
|
-
args.first
|
20
|
-
end
|
16
|
+
def check_name_arg!
|
17
|
+
return if args.first && !args.first.empty?
|
21
18
|
|
22
|
-
|
23
|
-
|
19
|
+
raise Command::ArgumentError,
|
20
|
+
"Please provide a name when using the scaffold generator!"
|
24
21
|
end
|
25
22
|
end
|
26
23
|
end
|