shaf 1.6.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/iana_link_relations.csv.gz +0 -0
  4. data/lib/shaf/alps/attribute_serializer.rb +41 -0
  5. data/lib/shaf/alps/json_serializer.rb +50 -0
  6. data/lib/shaf/alps/relation_serializer.rb +70 -0
  7. data/lib/shaf/app.rb +32 -7
  8. data/lib/shaf/authenticator/base.rb +161 -0
  9. data/lib/shaf/authenticator/basic_auth.rb +25 -0
  10. data/lib/shaf/authenticator/challenge.rb +32 -0
  11. data/lib/shaf/authenticator/parameter.rb +31 -0
  12. data/lib/shaf/authenticator/request.rb +17 -0
  13. data/lib/shaf/authenticator.rb +56 -0
  14. data/lib/shaf/command/base.rb +4 -0
  15. data/lib/shaf/command/console.rb +1 -1
  16. data/lib/shaf/command/generate.rb +5 -2
  17. data/lib/shaf/command/new.rb +24 -7
  18. data/lib/shaf/command/server.rb +5 -1
  19. data/lib/shaf/command/templates/Gemfile.erb +1 -0
  20. data/{templates/config/settings.yml → lib/shaf/command/templates/config/settings.yml.erb} +9 -12
  21. data/lib/shaf/errors.rb +11 -0
  22. data/lib/shaf/extensions/api_routes.rb +60 -0
  23. data/lib/shaf/extensions/authorize.rb +11 -9
  24. data/lib/shaf/extensions/log.rb +1 -1
  25. data/lib/shaf/extensions/resource_uris.rb +95 -137
  26. data/lib/shaf/extensions/symbolic_routes.rb +9 -19
  27. data/lib/shaf/extensions.rb +3 -3
  28. data/lib/shaf/formable/builder.rb +58 -19
  29. data/lib/shaf/formable/form.rb +14 -11
  30. data/lib/shaf/formable.rb +10 -24
  31. data/lib/shaf/generator/base.rb +84 -3
  32. data/lib/shaf/generator/controller.rb +30 -42
  33. data/lib/shaf/generator/doc.rb +17 -0
  34. data/lib/shaf/generator/forms.rb +11 -14
  35. data/lib/shaf/generator/helper.rb +2 -1
  36. data/lib/shaf/generator/migration/add_column.rb +0 -4
  37. data/lib/shaf/generator/migration/add_index.rb +0 -4
  38. data/lib/shaf/generator/migration/base.rb +15 -3
  39. data/lib/shaf/generator/migration/create_table.rb +0 -4
  40. data/lib/shaf/generator/migration/drop_column.rb +0 -4
  41. data/lib/shaf/generator/migration/rename_column.rb +0 -4
  42. data/lib/shaf/generator/migration/type.rb +4 -26
  43. data/lib/shaf/generator/migration/types.rb +45 -16
  44. data/lib/shaf/generator/model.rb +29 -15
  45. data/lib/shaf/generator/policy.rb +8 -14
  46. data/lib/shaf/generator/profile.rb +47 -0
  47. data/lib/shaf/generator/scaffold.rb +6 -9
  48. data/lib/shaf/generator/serializer.rb +64 -98
  49. data/lib/shaf/generator/templates/api/controller.rb.erb +13 -13
  50. data/lib/shaf/generator/templates/api/forms.rb.erb +2 -2
  51. data/lib/shaf/generator/templates/api/model.rb.erb +1 -1
  52. data/lib/shaf/generator/templates/api/policy.rb.erb +2 -2
  53. data/lib/shaf/generator/templates/api/profile.rb.erb +16 -0
  54. data/lib/shaf/generator/templates/api/serializer.rb.erb +3 -3
  55. data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +15 -16
  56. data/lib/shaf/generator/templates/spec/serializer_spec.rb.erb +5 -5
  57. data/lib/shaf/generator.rb +2 -0
  58. data/lib/shaf/helpers/authentication.rb +79 -0
  59. data/lib/shaf/helpers/paginate.rb +1 -1
  60. data/lib/shaf/helpers/payload.rb +14 -34
  61. data/lib/shaf/helpers/vary.rb +8 -0
  62. data/lib/shaf/helpers.rb +4 -0
  63. data/lib/shaf/logger.rb +12 -0
  64. data/lib/shaf/parser/base.rb +44 -0
  65. data/lib/shaf/parser/form_data.rb +15 -0
  66. data/lib/shaf/parser/json.rb +26 -0
  67. data/lib/shaf/parser.rb +65 -0
  68. data/lib/shaf/profile/attribute.rb +29 -0
  69. data/lib/shaf/profile/evaluator.rb +46 -0
  70. data/lib/shaf/profile/relation.rb +29 -0
  71. data/lib/shaf/profile/unique_id.rb +58 -0
  72. data/lib/shaf/profile.rb +115 -0
  73. data/lib/shaf/profiles/shaf_basic.rb +20 -0
  74. data/lib/shaf/profiles/shaf_error.rb +49 -0
  75. data/lib/shaf/profiles/shaf_form.rb +110 -0
  76. data/lib/shaf/profiles.rb +46 -0
  77. data/lib/shaf/registrable_factory.rb +62 -32
  78. data/lib/shaf/responder/alps_json.rb +25 -0
  79. data/lib/shaf/responder/base.rb +20 -17
  80. data/lib/shaf/responder/hal.rb +66 -5
  81. data/lib/shaf/responder/html.rb +43 -16
  82. data/lib/shaf/responder/problem_json.rb +2 -2
  83. data/lib/shaf/responder.rb +41 -2
  84. data/lib/shaf/router.rb +65 -12
  85. data/lib/shaf/serializer.rb +35 -0
  86. data/lib/shaf/settings.rb +25 -12
  87. data/lib/shaf/spec/authenticator.rb +13 -0
  88. data/lib/shaf/spec/base.rb +1 -1
  89. data/lib/shaf/spec/http_method_utils.rb +1 -1
  90. data/lib/shaf/spec/integration_spec.rb +26 -14
  91. data/lib/shaf/spec/payload_utils.rb +2 -2
  92. data/lib/shaf/spec.rb +1 -0
  93. data/lib/shaf/supported_http_methods.rb +15 -0
  94. data/lib/shaf/tasks/routes_task.rb +14 -17
  95. data/lib/shaf/tasks.rb +0 -1
  96. data/lib/shaf/upgrade/manifest.rb +11 -2
  97. data/lib/shaf/upgrade/package.rb +73 -45
  98. data/lib/shaf/upgrade/version.rb +11 -10
  99. data/lib/shaf/utils.rb +19 -5
  100. data/lib/shaf/version.rb +3 -1
  101. data/lib/shaf/yard/attribute_method_handler.rb +19 -0
  102. data/lib/shaf/yard/attribute_object.rb +30 -0
  103. data/lib/shaf/yard/base_method_handler.rb +30 -0
  104. data/lib/shaf/yard/link_method_handler.rb +39 -0
  105. data/lib/shaf/yard/link_object.rb +60 -0
  106. data/lib/shaf/yard/nested_attributes.rb +37 -0
  107. data/lib/shaf/yard/parser.rb +64 -0
  108. data/lib/shaf/yard/profile_method_handler.rb +51 -0
  109. data/lib/shaf/yard/profile_object.rb +21 -0
  110. data/lib/shaf/yard/resource_object.rb +55 -0
  111. data/lib/shaf/yard/serializer_handler.rb +27 -0
  112. data/lib/shaf/yard.rb +34 -0
  113. data/lib/shaf.rb +6 -0
  114. data/templates/Rakefile +0 -6
  115. data/templates/api/controllers/base_controller.rb +0 -12
  116. data/templates/api/controllers/docs_controller.rb +5 -3
  117. data/templates/api/controllers/root_controller.rb +7 -1
  118. data/templates/api/policies/base_policy.rb +2 -0
  119. data/templates/api/serializers/base_serializer.rb +1 -3
  120. data/templates/api/serializers/error_serializer.rb +1 -5
  121. data/templates/api/serializers/form_serializer.rb +1 -5
  122. data/templates/api/serializers/root_serializer.rb +0 -11
  123. data/templates/api/serializers/validation_error_serializer.rb +1 -5
  124. data/templates/config/bootstrap.rb +1 -2
  125. data/templates/config/directories.rb +52 -44
  126. data/templates/config/helpers.rb +1 -1
  127. data/templates/config/initializers/authentication.rb +18 -0
  128. data/templates/config/initializers/db_migrations.rb +2 -2
  129. data/templates/config/initializers/logging.rb +2 -2
  130. data/templates/config/initializers/middleware.rb +6 -0
  131. data/templates/config/initializers.rb +52 -8
  132. data/templates/config.ru +1 -1
  133. data/templates/spec/spec_helper.rb +5 -0
  134. data/upgrades/0.5.0.tar.gz +0 -0
  135. data/upgrades/1.0.4.tar.gz +0 -0
  136. data/upgrades/1.1.0.tar.gz +0 -0
  137. data/upgrades/1.6.1.tar.gz +0 -0
  138. data/upgrades/2.0.0.tar.gz +0 -0
  139. data/upgrades/3.0.0.tar.gz +0 -0
  140. data/yard_templates/api_doc/doc_index/html/body.erb +3 -0
  141. data/yard_templates/api_doc/doc_index/setup.rb +8 -0
  142. data/yard_templates/api_doc/html/css/api-doc.css +222 -0
  143. data/yard_templates/api_doc/html/favicon.ico +0 -0
  144. data/yard_templates/api_doc/html/js/switch_tab.js +17 -0
  145. data/yard_templates/api_doc/html/setup.rb +59 -0
  146. data/yard_templates/api_doc/layout/html/footer.erb +3 -0
  147. data/yard_templates/api_doc/layout/html/header.erb +7 -0
  148. data/yard_templates/api_doc/layout/html/layout.erb +13 -0
  149. data/yard_templates/api_doc/layout/setup.rb +24 -0
  150. data/yard_templates/api_doc/profile/html/attributes.erb +10 -0
  151. data/yard_templates/api_doc/profile/html/profile.erb +6 -0
  152. data/yard_templates/api_doc/profile/html/relations.erb +10 -0
  153. data/yard_templates/api_doc/profile/setup.rb +38 -0
  154. data/yard_templates/api_doc/profile_attribute/html/attribute.erb +23 -0
  155. data/yard_templates/api_doc/profile_attribute/setup.rb +21 -0
  156. data/yard_templates/api_doc/profile_relation/html/relation.erb +37 -0
  157. data/yard_templates/api_doc/profile_relation/setup.rb +41 -0
  158. data/yard_templates/api_doc/resource/html/attributes.erb +10 -0
  159. data/yard_templates/api_doc/resource/html/profile.erb +14 -0
  160. data/yard_templates/api_doc/resource/html/relations.erb +10 -0
  161. data/yard_templates/api_doc/resource/html/resource.erb +5 -0
  162. data/yard_templates/api_doc/resource/setup.rb +56 -0
  163. data/yard_templates/api_doc/resource_attribute/html/attribute.erb +23 -0
  164. data/yard_templates/api_doc/resource_attribute/setup.rb +20 -0
  165. data/yard_templates/api_doc/resource_relation/html/relation.erb +47 -0
  166. data/yard_templates/api_doc/resource_relation/setup.rb +80 -0
  167. data/yard_templates/api_doc/setup.rb +31 -0
  168. data/yard_templates/api_doc/sidebar/html/profile_list.erb +8 -0
  169. data/yard_templates/api_doc/sidebar/html/search.erb +7 -0
  170. data/yard_templates/api_doc/sidebar/html/serializer_list.erb +8 -0
  171. data/yard_templates/api_doc/sidebar/html/sidebar.erb +13 -0
  172. data/yard_templates/api_doc/sidebar/setup.rb +56 -0
  173. data.tar.gz.sig +2 -2
  174. metadata +143 -38
  175. metadata.gz.sig +0 -0
  176. data/lib/shaf/api_doc/comment.rb +0 -27
  177. data/lib/shaf/api_doc/document.rb +0 -137
  178. data/lib/shaf/extensions/current_user.rb +0 -48
  179. data/lib/shaf/middleware.rb +0 -1
  180. data/lib/shaf/responder/hal_serializable.rb +0 -64
  181. data/lib/shaf/tasks/api_doc_task.rb +0 -125
@@ -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)
@@ -112,7 +115,7 @@ module Shaf
112
115
  end
113
116
 
114
117
  def submit_element
115
- %Q(<div class="form--input-group"><input type="submit" class="button" value="Submit"</div>)
118
+ %Q(<div class="form--input-group"><input type="submit" class="button" value="#{submit}"</div>)
116
119
  end
117
120
  end
118
121
  end
data/lib/shaf/formable.rb CHANGED
@@ -3,44 +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
- return unless defined? $logger
22
-
23
- $logger.info <<~MSG
24
-
25
-
26
- DEPRECATED method ::form in #{self}
27
- Declare forms in a separate class extending Shaf::Formable with the class method forms_for!
28
- MSG
29
- end
30
-
31
- # New way of writing forms in a separate class/file
32
18
  def forms_for(clazz, &block)
33
19
  builder = Formable::Builder.new(&block)
34
- builder.forms.each do |form|
35
- next unless form.action
36
- method_name = "#{form.action}_form"
20
+ builder.forms.each do |form_wrapper|
21
+ method_name = form_wrapper.method_name
22
+ next unless method_name
37
23
 
38
- Formable.add_class_reader(clazz, method_name, form.dup)
24
+ form = form_wrapper.form
39
25
 
40
- if instance_accessor = builder.instance_accessor_for(form)
41
- prefill_form = instance_accessor.prefill?
42
- Formable.add_instance_reader(clazz, method_name, form.dup, prefill_form)
43
- end
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?)
44
30
  end
45
31
  end
46
32
  alias form_for forms_for
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'erb'
5
+ require 'file_transactions'
5
6
  require 'shaf/generator/helper'
6
7
 
7
8
  module Shaf
@@ -22,6 +23,10 @@ module Shaf
22
23
  @usage = str || block
23
24
  end
24
25
 
26
+ def identified_by
27
+ @identifiers
28
+ end
29
+
25
30
  def options(option_parser, options); end
26
31
  end
27
32
 
@@ -32,6 +37,60 @@ module Shaf
32
37
 
33
38
  def call; end
34
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
+
35
94
  def template_dir
36
95
  File.expand_path('templates', __dir__)
37
96
  end
@@ -55,10 +114,32 @@ module Shaf
55
114
  raise
56
115
  end
57
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
+
58
141
  def write_output(file, content)
59
- dir = File.dirname(file)
60
- FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
61
- File.write(file, content)
142
+ FileTransactions::CreateFileCommand.execute(file) { content }
62
143
  puts "Added: #{file}"
63
144
  end
64
145
  end
@@ -1,3 +1,5 @@
1
+ require 'file_transactions'
2
+
1
3
  module Shaf
2
4
  module Generator
3
5
  class Controller < Base
@@ -11,24 +13,7 @@ module Shaf
11
13
  add_link_to_root
12
14
  end
13
15
 
14
- def params
15
- args[1..-1].map { |param| param.split(':')}
16
- end
17
-
18
- def name
19
- n = args.first || ''
20
- return n unless n.empty?
21
- raise Command::ArgumentError,
22
- 'Please provide a controller name when using the controller generator!'
23
- end
24
-
25
- def model_class_name
26
- Utils.model_name(name)
27
- end
28
-
29
- def plural_name
30
- Utils.pluralize(name)
31
- end
16
+ private
32
17
 
33
18
  def pluralized_model_name
34
19
  Utils.pluralize(model_class_name)
@@ -42,21 +27,31 @@ module Shaf
42
27
  'spec/integration_spec.rb'
43
28
  end
44
29
 
45
- def target
46
- "api/controllers/#{plural_name}_controller.rb"
30
+ def target_dir
31
+ 'api/controllers'
32
+ end
33
+
34
+ def target_name
35
+ "#{plural_name}_controller.rb"
47
36
  end
48
37
 
49
38
  def spec_target
50
- "spec/integration/#{plural_name}_controller_spec.rb"
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)
51
44
  end
52
45
 
53
46
  def create_controller
54
47
  content = render(template, opts)
48
+ content = wrap_in_module(content, module_name)
55
49
  write_output(target, content)
56
50
  end
57
51
 
58
52
  def create_integration_spec
59
53
  content = render(spec_template, opts)
54
+ content = wrap_in_module(content, module_name, search: "describe #{model_class_name}")
60
55
  write_output(spec_target, content)
61
56
  end
62
57
 
@@ -64,11 +59,14 @@ module Shaf
64
59
  {
65
60
  name: name,
66
61
  plural_name: plural_name,
62
+ resource_name: resource_name,
63
+ collection_name: collection_name,
67
64
  serializer_class_name: "#{model_class_name}Serializer",
68
65
  model_class_name: model_class_name,
69
66
  controller_class_name: "#{pluralized_model_name}Controller",
70
67
  policy_class_name: "#{model_class_name}Policy",
71
- policy_file: "policies/#{name}_policy",
68
+ policy_file: policy_file,
69
+ namespace: namespace,
72
70
  params: params
73
71
  }
74
72
  end
@@ -81,31 +79,21 @@ module Shaf
81
79
  end
82
80
  added = false
83
81
  content = []
84
- File.readlines(file).reverse_each do |line|
85
- if match = !added && line.match(/^(\s*)link /)
86
- content.unshift link_content(match[1].to_s)
87
- added = true
82
+ FileTransactions::ChangeFileCommand.execute(file) do
83
+ File.readlines(file).reverse_each do |line|
84
+ if match = !added && line.match(/^(\s*)link /)
85
+ content.unshift link_content(match[1].to_s)
86
+ added = true
87
+ end
88
+ content.unshift(line)
88
89
  end
89
- content.unshift(line)
90
+ File.open(file, 'w') { |f| f.puts content }
91
+ puts "Modified: #{file}"
90
92
  end
91
- File.open(file, 'w') { |f| f.puts content }
92
- puts "Modified: #{file}"
93
93
  end
94
94
 
95
95
  def link_content(indentation = '')
96
- <<~DOC.split("\n").map { |line| "#{indentation}#{line}" }
97
-
98
- # Auto generated doc:
99
- # Link to the collection of #{plural_name}.
100
- # Method: GET
101
- # Example:
102
- # ```
103
- # curl -H "Accept: application/hal+json" \\
104
- # -H "Authorization: abcdef" \\
105
- # /#{plural_name}
106
- #```
107
- link :#{plural_name}, #{plural_name}_uri
108
- DOC
96
+ "#{indentation}link :#{plural_name}, #{collection_name}_uri"
109
97
  end
110
98
  end
111
99
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shaf
4
+ module Generator
5
+ class Doc < Base
6
+ identifier %r{\Adoc(\b|umentation)\Z}
7
+ usage 'generate doc [SERIALIZER_NAME] [..]'
8
+
9
+ def call
10
+ require 'shaf/yard'
11
+ name = String(args[0]).strip
12
+ Shaf::Yard::Parser.call(name: name)
13
+ YARD::Templates::Engine.render(template: :api_doc, format: :html)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -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,18 +18,24 @@ module Shaf
27
18
  'api/forms.rb'
28
19
  end
29
20
 
30
- def target
31
- "api/forms/#{model_name}_forms.rb"
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)
32
+ # FIXME: Append if file exists!
36
33
  write_output(target, content)
37
34
  end
38
35
 
39
36
  def opts
40
37
  {
41
- model_name: model_name,
38
+ model_name: name,
42
39
  class_name: class_name,
43
40
  model_class_name: model_class_name,
44
41
  fields: fields
@@ -10,7 +10,8 @@ module Shaf
10
10
 
11
11
  def print(lines, indent_level = 2)
12
12
  strip_blank(lines).inject do |result, line|
13
- result + "\n#{i(indent_level) unless line.empty?}#{line}"
13
+ indent = i(indent_level) unless line.empty?
14
+ result + "\n#{indent}#{line}"
14
15
  end.chomp
15
16
  end
16
17
 
@@ -21,10 +21,6 @@ module Shaf
21
21
  "add_#{cols.join('_')}_to_#{table_name}"
22
22
  end
23
23
 
24
- def table_name
25
- args.first
26
- end
27
-
28
24
  def compile_changes
29
25
  add_change add_columns_change
30
26
  end
@@ -16,10 +16,6 @@ module Shaf
16
16
  "add_#{column}_index_to_#{table_name}"
17
17
  end
18
18
 
19
- def table_name
20
- args.first
21
- end
22
-
23
19
  def compile_changes
24
20
  add_change add_index_change
25
21
  end
@@ -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
@@ -42,9 +50,13 @@ module Shaf
42
50
 
43
51
  def column_def(str, create: true)
44
52
  _, col_type = str.split(':')
45
- type = Type.find(col_type)
46
- raise "No supported DB column types for: #{col_type}" unless type
47
- type.build(str, create: create, alter: !create)
53
+ type = Types.find(col_type)
54
+ return type.build(str, create: create, alter: !create) if type
55
+
56
+ raise <<~ERR
57
+ No supported DB column types for: #{col_type}
58
+ Supported types: #{Types.all.map(&:name).join(', ')}
59
+ ERR
48
60
  end
49
61
 
50
62
  def target(name)
@@ -11,10 +11,6 @@ module Shaf
11
11
  raise "Please provide a table name when generation a create table migration"
12
12
  end
13
13
 
14
- def table_name
15
- args.first || ""
16
- end
17
-
18
14
  def compile_migration_name
19
15
  "create_#{table_name}_table"
20
16
  end
@@ -24,10 +24,6 @@ module Shaf
24
24
  add_change drop_column_change
25
25
  end
26
26
 
27
- def table_name
28
- args.first || ""
29
- end
30
-
31
27
  def column
32
28
  args[1] || ""
33
29
  end
@@ -23,10 +23,6 @@ module Shaf
23
23
  add_change rename_column_change
24
24
  end
25
25
 
26
- def table_name
27
- args.first || ""
28
- end
29
-
30
26
  def from_col
31
27
  args[1] || ""
32
28
  end
@@ -4,34 +4,12 @@ module Shaf
4
4
  class Type
5
5
  attr_reader :name, :create_template, :alter_template, :validator
6
6
 
7
- class << self
8
- def add(name, **kwargs)
9
- new(name, **kwargs).tap do |type|
10
- types[type.name] = type
11
- end
12
- end
13
-
14
- def find(str)
15
- name, _ = str.to_s.split(',', 2)
16
- types[name.to_sym]
17
- end
18
-
19
- private
20
-
21
- def types
22
- @types ||= {}
23
- end
24
-
25
- def clear
26
- @types.clear if defined? @types
27
- end
28
- end
29
-
30
7
  def initialize(str, create_template:, alter_template:, validator: nil)
31
8
  @name = str.downcase.to_sym
32
- @create_template = create_template
33
- @alter_template = alter_template
34
- @validator = validator
9
+ @create_template = create_template.freeze
10
+ @alter_template = alter_template.freeze
11
+ @validator = validator.freeze
12
+ freeze
35
13
  end
36
14
 
37
15
  def build(str, create: false, alter: false)