shaf 2.1.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -11,19 +11,8 @@ module Shaf
11
11
  create_profile
12
12
  end
13
13
 
14
- def name
15
- n = args.first || ""
16
- return n unless n.empty?
17
- raise Command::ArgumentError,
18
- "Please provide a model name when using the serializer generator!"
19
- end
20
-
21
- def plural_name
22
- Utils.pluralize(name)
23
- end
24
-
25
- def model_class_name
26
- Utils.model_name(name)
14
+ def serializer_class_name
15
+ "#{model_class_name}Serializer"
27
16
  end
28
17
 
29
18
  def policy_class_name
@@ -38,21 +27,31 @@ module Shaf
38
27
  'spec/serializer_spec.rb'
39
28
  end
40
29
 
41
- def target
42
- "api/serializers/#{name}_serializer.rb"
30
+ def target_dir
31
+ 'api/serializers'
32
+ end
33
+
34
+ def target_name
35
+ "#{name}_serializer.rb"
43
36
  end
44
37
 
45
38
  def spec_target
46
- "spec/serializers/#{name}_serializer_spec.rb"
39
+ target(directory: 'spec/serializers', name: "#{name}_serializer_spec.rb")
40
+ end
41
+
42
+ def policy_file
43
+ File.join(['policies', namespace, "#{name}_policy"].compact)
47
44
  end
48
45
 
49
46
  def create_serializer
50
47
  content = render(template, opts)
48
+ content = wrap_in_module(content, module_name)
51
49
  write_output(target, content)
52
50
  end
53
51
 
54
52
  def create_serializer_spec
55
53
  content = render(spec_template, opts)
54
+ content = wrap_in_module(content, module_name, search: "describe #{serializer_class_name}")
56
55
  write_output(spec_target, content)
57
56
  end
58
57
 
@@ -74,16 +73,16 @@ module Shaf
74
73
 
75
74
  def profile_with_doc
76
75
  doc = <<~DOC
77
- # Adds a link to the '#{name}' profile and a curie. By default the
76
+ # Adds a link to the '#{resource_name}' profile and a curie. By default the
78
77
  # curie prefix is 'doc', use the `curie_prefix` keyword argument to
79
78
  # change this.
80
79
  # Note: the target of the profile link and the curie will be set to
81
- # `profile_uri('#{name}')` resp. `doc_curie_uri('#{name}')`. To
80
+ # `profile_uri('#{resource_name}')` resp. `doc_curie_uri('#{resource_name}')`. To
82
81
  # create links for external profiles or curies, delete the next line
83
82
  # and use `::link` and/or `::curie` instead.
84
83
  DOC
85
84
 
86
- doc.split("\n") << %Q(profile #{Utils.symbol_string(name)})
85
+ doc.split("\n") << %Q(profile #{Utils.symbol_string(resource_name)})
87
86
  end
88
87
 
89
88
  def links_with_doc
@@ -98,7 +97,7 @@ module Shaf
98
97
  def collection_link
99
98
  link(
100
99
  rel: "collection",
101
- uri_helper: "#{plural_name}_uri",
100
+ uri_helper: "#{collection_name}_uri",
102
101
  kwargs: {embed_depth: 0}
103
102
  )
104
103
  end
@@ -106,21 +105,21 @@ module Shaf
106
105
  def self_link
107
106
  link(
108
107
  rel: "self",
109
- uri_helper: "#{name}_uri(resource)"
108
+ uri_helper: "#{resource_name}_uri(resource)"
110
109
  )
111
110
  end
112
111
 
113
112
  def edit_link
114
113
  link(
115
114
  rel: "edit-form",
116
- uri_helper: "edit_#{name}_uri(resource)"
115
+ uri_helper: "edit_#{resource_name}_uri(resource)"
117
116
  )
118
117
  end
119
118
 
120
119
  def delete_link
121
120
  link(
122
121
  rel: "delete",
123
- uri_helper: "#{name}_uri(resource)",
122
+ uri_helper: "#{resource_name}_uri(resource)",
124
123
  kwargs: {curie: :doc}
125
124
  )
126
125
  end
@@ -128,7 +127,7 @@ module Shaf
128
127
  def create_link
129
128
  link(
130
129
  rel: "create-form",
131
- uri_helper: "new_#{name}_uri"
130
+ uri_helper: "new_#{resource_name}_uri"
132
131
  )
133
132
  end
134
133
 
@@ -147,9 +146,9 @@ module Shaf
147
146
  def collection_with_doc
148
147
  <<~EOS.split("\n")
149
148
  collection of: '#{plural_name}' do
150
- curie(:doc) { doc_curie_uri('#{name}') }
149
+ curie(:doc) { doc_curie_uri('#{resource_name}') }
151
150
 
152
- link :self, #{plural_name}_uri
151
+ link :self, #{collection_name}_uri
153
152
  link :up, root_uri
154
153
 
155
154
  #{create_link.join("\n ")}
@@ -160,10 +159,12 @@ module Shaf
160
159
  def opts
161
160
  {
162
161
  name: name,
163
- class_name: "#{model_class_name}Serializer",
162
+ resource_name: resource_name,
163
+ collection_name: collection_name,
164
+ class_name: serializer_class_name,
164
165
  model_class_name: model_class_name,
165
166
  policy_class_name: policy_class_name,
166
- policy_name: "#{name}_policy",
167
+ policy_file: policy_file,
167
168
  attribute_names: attribute_names,
168
169
  link_relations: link_relations,
169
170
  profile_with_doc: profile_with_doc,
@@ -174,12 +175,12 @@ module Shaf
174
175
  end
175
176
 
176
177
  def create_policy
177
- policy_args = ["policy", name, *attribute_names]
178
+ policy_args = ["policy", name_arg, *attribute_names]
178
179
  Generator::Factory.create(*policy_args, **options).call
179
180
  end
180
181
 
181
182
  def create_profile
182
- profile_args = ["profile", name, *attributes]
183
+ profile_args = ["profile", name_arg, *attributes]
183
184
  Generator::Factory.create(*profile_args, **options).call
184
185
  end
185
186
  end
@@ -4,45 +4,45 @@ class <%= controller_class_name %> < BaseController
4
4
 
5
5
  authorize_with <%= policy_class_name %>
6
6
 
7
- resource_uris_for :<%= name %>
7
+ resource_uris_for :<%= name %><%= namespace ? ", namespace: '#{namespace}'" : "" %>
8
8
 
9
- get :<%= plural_name %>_path do
9
+ get :<%= collection_name %>_path do
10
10
  authorize! :read
11
11
  collection = paginate(<%= model_class_name %>.order(:created_at).reverse)
12
12
  respond_with_collection collection, serializer: <%= serializer_class_name %>
13
13
  end
14
14
 
15
- get :new_<%= name %>_path do
15
+ get :new_<%= resource_name %>_path do
16
16
  authorize! :read
17
17
  cache_control(:private, http_cache_max_age: :short)
18
18
  respond_with create_form
19
19
  end
20
20
 
21
- post :<%= plural_name %>_path do
21
+ post :<%= collection_name %>_path do
22
22
  authorize! :write
23
23
  <%= name %> = <%= model_class_name %>.create(<%= name %>_params)
24
- headers('Location' => <%= name %>_uri(<%= name %>))
24
+ headers('Location' => <%= resource_name %>_uri(<%= name %>))
25
25
  respond_with <%= name %>, status: 201
26
26
  end
27
27
 
28
- get :<%= name %>_path do
28
+ get :<%= resource_name %>_path do
29
29
  authorize! :read
30
30
  respond_with <%= name %>
31
31
  end
32
32
 
33
- get :edit_<%= name %>_path do
33
+ get :edit_<%= resource_name %>_path do
34
34
  authorize! :write
35
35
  cache_control(:private, http_cache_max_age: :short)
36
36
  respond_with edit_form
37
37
  end
38
38
 
39
- put :<%= name %>_path do
39
+ put :<%= resource_name %>_path do
40
40
  authorize! :write
41
41
  <%= name %>.update(<%= name %>_params)
42
42
  respond_with <%= name %>
43
43
  end
44
44
 
45
- delete :<%= name %>_path do
45
+ delete :<%= resource_name %>_path do
46
46
  authorize! :write
47
47
  <%= name %>.destroy
48
48
  status 204
@@ -62,15 +62,15 @@ class <%= controller_class_name %> < BaseController
62
62
 
63
63
  def create_form
64
64
  <%= model_class_name %>.create_form.tap do |form|
65
- form.self_link = new_<%= name %>_uri
66
- form.href = <%= plural_name %>_uri
65
+ form.self_link = new_<%= resource_name %>_uri
66
+ form.href = <%= collection_name %>_uri
67
67
  end
68
68
  end
69
69
 
70
70
  def edit_form
71
71
  <%= name %>.edit_form.tap do |form|
72
- form.self_link = edit_<%= name %>_uri(<%= name %>)
73
- form.href = <%= name %>_uri(<%= name %>)
72
+ form.self_link = edit_<%= resource_name %>_uri(<%= name %>)
73
+ form.href = <%= resource_name %>_uri(<%= name %>)
74
74
  end
75
75
  end
76
76
  end
@@ -4,12 +4,12 @@ class <%= class_name %>
4
4
  forms_for(<%= model_class_name %>) do
5
5
  <%= fields.join("\n ") %>
6
6
 
7
- create do
7
+ create_form do
8
8
  title 'Create <%= model_class_name %>'
9
9
  name 'create-<%= model_name %>'
10
10
  end
11
11
 
12
- edit do
12
+ edit_form do
13
13
  instance_accessor
14
14
  title 'Update <%= model_class_name %>'
15
15
  name 'update-<%= model_name %>'
@@ -1,4 +1,4 @@
1
- class <%= class_name %> < Sequel::Model
1
+ class <%= class_name %> < Sequel::Model(:<%= table_name %>)
2
2
 
3
3
  end
4
4
 
@@ -1,6 +1,6 @@
1
1
  module Profiles
2
2
  class <%= profile_class_name %> < Shaf::Profile
3
- name '<%= profile_name %>'
3
+ name '<%= resource_name %>'
4
4
 
5
5
  doc 'FIXME: replace this with a description of the <%= profile_name %> profile'
6
6
 
@@ -1,5 +1,5 @@
1
1
  require 'serializers/base_serializer'
2
- require 'policies/<%= policy_name %>'
2
+ require '<%= policy_file %>'
3
3
 
4
4
  class <%= class_name %> < BaseSerializer
5
5
 
@@ -4,10 +4,10 @@ describe <%= model_class_name %>, type: :integration do
4
4
 
5
5
  it "returns a <%= name %>" do
6
6
  <%= name %> = <%= model_class_name %>.create
7
- get <%= name %>_uri(<%= name %>)
7
+ get <%= resource_name %>_uri(<%= name %>)
8
8
  _(status).must_equal 200
9
9
  _(link_rels).must_include(:self)
10
- _(links[:self][:href]).must_equal <%= name %>_uri(<%= name %>)
10
+ _(links[:self][:href]).must_equal <%= resource_name %>_uri(<%= name %>)
11
11
  <% params.each do |param| -%>
12
12
  _(attributes).must_include(:'<%= param[0] %>')
13
13
  <% end -%>
@@ -16,10 +16,10 @@ describe <%= model_class_name %>, type: :integration do
16
16
  it "lists all <%= plural_name %>" do
17
17
  2.times { <%= model_class_name %>.create }
18
18
 
19
- get <%= plural_name %>_uri
19
+ get <%= collection_name %>_uri
20
20
  _(status).must_equal 200
21
21
  _(link_rels).must_include(:self)
22
- _(links[:self][:href]).must_include <%= plural_name %>_uri
22
+ _(links[:self][:href]).must_include <%= collection_name %>_uri
23
23
  _(embedded(:'<%= plural_name %>').size).must_equal 2
24
24
 
25
25
  each_embedded :'<%= plural_name %>' do
@@ -31,12 +31,12 @@ describe <%= model_class_name %>, type: :integration do
31
31
  end
32
32
  <% if params.size > 0 %>
33
33
  it "can create <%= plural_name %>" do
34
- get <%= plural_name %>_uri
34
+ get <%= collection_name %>_uri
35
35
 
36
36
  _(link_rels).must_include(:'create-form')
37
37
  follow_rel :'create-form'
38
- _(links[:self][:href]).must_equal new_<%= name %>_uri
39
- _(attributes[:href]).must_equal <%= plural_name %>_uri
38
+ _(links[:self][:href]).must_equal new_<%= resource_name %>_uri
39
+ _(attributes[:href]).must_equal <%= collection_name %>_uri
40
40
  _(attributes[:method]).must_equal "POST"
41
41
  _(attributes[:name]).must_equal "create-<%= name %>"
42
42
  _(attributes[:title]).must_equal "Create <%= model_class_name %>"
@@ -49,9 +49,9 @@ describe <%= model_class_name %>, type: :integration do
49
49
  _(link_rels).must_include(:self)
50
50
  _(headers["Location"]).must_equal links[:self][:href]
51
51
 
52
- get <%= plural_name %>_uri
52
+ get <%= collection_name %>_uri
53
53
  _(status).must_equal 200
54
- _(links[:self][:href]).must_include <%= plural_name %>_uri
54
+ _(links[:self][:href]).must_include <%= collection_name %>_uri
55
55
  _(embedded(:'<%= plural_name %>').size).must_equal 1
56
56
 
57
57
  embedded :'<%= plural_name %>' do
@@ -68,14 +68,14 @@ describe <%= model_class_name %>, type: :integration do
68
68
 
69
69
  it "<%= plural_name %> can be updated" do
70
70
  <%= name %> = <%= model_class_name %>.create
71
- get <%= name %>_uri(<%= name %>)
71
+ get <%= resource_name %>_uri(<%= name %>)
72
72
  _(status).must_equal 200
73
73
 
74
74
  _(link_rels).must_include(:'edit-form')
75
75
  follow_rel :'edit-form'
76
76
 
77
- _(links[:self][:href]).must_equal edit_<%= name %>_uri(<%= name %>)
78
- _(attributes[:href]).must_equal <%= name %>_uri(<%= name %>)
77
+ _(links[:self][:href]).must_equal edit_<%= resource_name %>_uri(<%= name %>)
78
+ _(attributes[:href]).must_equal <%= resource_name %>_uri(<%= name %>)
79
79
  _(attributes[:method]).must_equal "PUT"
80
80
  _(attributes[:name]).must_equal "update-<%= name %>"
81
81
  _(attributes[:title]).must_equal "Update <%= model_class_name %>"
@@ -91,14 +91,14 @@ describe <%= model_class_name %>, type: :integration do
91
91
 
92
92
  it "<%= plural_name %> can be deleted" do
93
93
  <%= name %> = <%= model_class_name %>.create
94
- get <%= name %>_uri(<%= name %>)
94
+ get <%= resource_name %>_uri(<%= name %>)
95
95
  _(status).must_equal 200
96
96
  _(link_rels).must_include(:'doc:delete')
97
97
 
98
98
  follow_rel(:'doc:delete', method: :delete)
99
99
  _(status).must_equal 204
100
100
 
101
- get <%= name %>_uri(<%= name %>)
101
+ get <%= resource_name %>_uri(<%= name %>)
102
102
  _(status).must_equal 404
103
103
  end
104
104
 
@@ -12,7 +12,7 @@ module Shaf
12
12
  unless collection.respond_to? :paginate
13
13
  log.warn "Trying to paginate a collection that doesn't " \
14
14
  "support pagination: #{collection}"
15
- return
15
+ return collection
16
16
  end
17
17
 
18
18
  per_page = params[:per_page].to_i if params[:per_page]
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'tempfile'
5
+ require 'uri'
6
+ require 'csv'
7
+
8
+ module Shaf
9
+ class LinkRelations
10
+ class LinkRelation
11
+ attr_reader :name, :description, :reference, :notes
12
+
13
+ def initialize(name, description, reference, notes)
14
+ @name = name.to_sym
15
+ @description = description.freeze
16
+ @reference = reference.freeze
17
+ @notes = notes.freeze
18
+ end
19
+ end
20
+
21
+ class << self
22
+ IANA_URL = URI('https://www.iana.org/assignments/link-relations/link-relations-1.csv')
23
+
24
+ def all
25
+ relations.values
26
+ end
27
+
28
+ def get(key)
29
+ load_iana
30
+ relations[key.to_sym]
31
+ end
32
+
33
+ def add(link_relation)
34
+ relations[link_relation.name.to_sym] = link_relation
35
+ end
36
+
37
+ private
38
+
39
+ def load_iana
40
+ return if @loaded
41
+
42
+ iana_csv.each do |name, desc, ref, notes|
43
+ next if name == 'Relation Name'
44
+ add LinkRelation.new(name, desc, ref, notes)
45
+ end
46
+
47
+ @loaded = true
48
+ end
49
+
50
+ def relations
51
+ @relations ||= {}
52
+ end
53
+
54
+ def tmp_file_name
55
+ File.join(Dir.tmpdir, 'shaf_iana_link_relations')
56
+ end
57
+
58
+ def iana_csv
59
+ CSV.new(iana_links)
60
+ end
61
+
62
+ def iana_links
63
+ return File.read(tmp_file_name) if File.readable? tmp_file_name
64
+
65
+ response = Net::HTTP.get_response(IANA_URL)
66
+
67
+ if response.code.to_i == 200
68
+ response.body.tap do |content|
69
+ File.open(tmp_file_name, 'w') { |file| file.write(content) }
70
+ end
71
+ else
72
+ Utils.iana_link_relations
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
data/lib/shaf/profile.rb CHANGED
@@ -5,6 +5,14 @@ require 'shaf/extensions/resource_uris'
5
5
 
6
6
  module Shaf
7
7
  class Profile
8
+ module NormalizeName
9
+ private def normalize(name)
10
+ name.to_s.downcase.tr('-', '_')
11
+ end
12
+ end
13
+
14
+ extend NormalizeName
15
+ include NormalizeName
8
16
  include Shaf::UriHelper
9
17
 
10
18
  class << self
@@ -98,18 +106,10 @@ module Shaf
98
106
  def evaluator
99
107
  Evaluator.new(parent: self)
100
108
  end
101
-
102
- def normalize(name)
103
- name.to_s.downcase.tr('-', '_')
104
- end
105
109
  end
106
110
 
107
111
  def name
108
112
  normalize(self.class.name)
109
113
  end
110
-
111
- def normalize(str)
112
- self.class.normalize(str)
113
- end
114
114
  end
115
115
  end
@@ -1,15 +1,58 @@
1
1
  module Shaf
2
2
  module RegistrableFactory
3
-
4
3
  class NotFoundError < StandardError; end
4
+ class NoIdentifiersError < StandardError
5
+
6
+ def initialize(clazz)
7
+ super <<~ERR
8
+ #{clazz} does not have an @identifiers ivar.
9
+ Did you perhaps forget to call `#{clazz}.identifier`?
10
+ ERR
11
+ end
12
+ end
13
+
14
+ class Entry
15
+ attr_reader :clazz
16
+
17
+ def initialize(clazz)
18
+ @clazz = clazz
19
+ end
20
+
21
+ def match?(strings)
22
+ raise NoIdentifiersError, clazz unless identifiers
23
+ return false if strings.size < identifiers.size
24
+ identifiers.zip(strings).all? { |pattern, str| matching_identifier? str, pattern }
25
+ end
26
+
27
+ def identifier_count
28
+ identifiers&.size || 0
29
+ end
30
+
31
+ def usage
32
+ clazz.instance_variable_get(:@usage)
33
+ end
34
+
35
+ private
36
+
37
+ def identifiers
38
+ clazz.identified_by
39
+ end
40
+
41
+ def matching_identifier?(str, pattern)
42
+ return false if pattern.nil? || str.nil? || str.empty?
43
+ pattern = pattern.to_s if pattern.is_a? Symbol
44
+ return str == pattern if pattern.is_a? String
45
+ !!str.match(pattern)
46
+ end
47
+ end
5
48
 
6
49
  def all
7
- reg.dup
50
+ reg.map(&:clazz)
8
51
  end
9
52
 
10
- def each
53
+ def each(&block)
11
54
  return all.each unless block_given?
12
- all.each { |c| yield c }
55
+ all.each(&block)
13
56
  end
14
57
 
15
58
  def size
@@ -17,34 +60,31 @@ module Shaf
17
60
  end
18
61
 
19
62
  def register(clazz)
20
- reg << clazz
63
+ reg << Entry.new(clazz)
21
64
  end
22
65
 
23
66
  def unregister(*str)
24
67
  return if str.empty? || !str.all?
25
- reg.delete_if { |clazz| matching_class? str, clazz }
68
+ reg.delete_if { |entry| entry.match? str }
26
69
  end
27
70
 
28
71
  def lookup(*str)
29
- return if str.empty? || !str.all?
30
- reg.select { |clazz| matching_class? str, clazz }
31
- .sort_by(&method(:identifier_count))
32
- .last
72
+ lookup_entry(*str)&.clazz
33
73
  end
34
74
 
35
75
  def usage
36
76
  reg.compact.map do |entry|
37
- usage = entry.instance_variable_get(:@usage)
77
+ usage = entry.usage
38
78
  usage.respond_to?(:call) ? usage.call : usage
39
79
  end
40
80
  end
41
81
 
42
82
  def create(*params, **options)
43
- clazz = lookup(*params)
44
- raise NotFoundError.new(%Q(Command '#{ARGV}' is not supported)) unless clazz
83
+ entry = lookup_entry(*params)
84
+ raise NotFoundError.new(%Q(Command '#{ARGV}' is not supported)) unless entry
45
85
 
46
- args = init_args(clazz, params)
47
- clazz.new(*args, **options)
86
+ args = init_args(entry, params)
87
+ entry.clazz.new(*args, **options)
48
88
  end
49
89
 
50
90
  private
@@ -53,25 +93,15 @@ module Shaf
53
93
  @reg ||= []
54
94
  end
55
95
 
56
- def matching_class?(strings, clazz)
57
- identifiers = clazz.instance_variable_get(:@identifiers)
58
- return false if strings.size < identifiers.size
59
- identifiers.zip(strings).all? { |pattern, str| matching_identifier? str, pattern }
60
- end
61
-
62
- def matching_identifier?(str, pattern)
63
- return false if pattern.nil? || str.nil? || str.empty?
64
- pattern = pattern.to_s if pattern.is_a? Symbol
65
- return str == pattern if pattern.is_a? String
66
- str.match(pattern) || false
67
- end
68
-
69
- def identifier_count(clazz)
70
- clazz.instance_variable_get(:@identifiers)&.size || 0
96
+ def lookup_entry(*str)
97
+ return if str.empty? || !str.all?
98
+ reg.select { |entry| entry.match? str }
99
+ .sort_by { |entry| entry.identifier_count }
100
+ .last
71
101
  end
72
102
 
73
- def init_args(clazz, params)
74
- first_non_id = identifier_count(clazz)
103
+ def init_args(entry, params)
104
+ first_non_id = entry.identifier_count
75
105
  params[first_non_id..-1]
76
106
  end
77
107
  end
@@ -16,7 +16,7 @@ module Shaf
16
16
 
17
17
  def hash
18
18
  {
19
- status: controller.status,
19
+ status: status,
20
20
  type: code,
21
21
  title: title,
22
22
  detail: resource.message,