sinja 0.2.0.beta2 → 1.0.0.pre1

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.
@@ -3,11 +3,24 @@ module Sinja
3
3
  module RelationshipRoutes
4
4
  module HasOne
5
5
  ACTIONS = %i[pluck prune graft].freeze
6
- CONFLICT_ACTIONS = %i[graft].freeze
7
6
 
8
7
  def self.registered(app)
9
8
  app.def_action_helpers(ACTIONS, app)
10
9
 
10
+ app.head '' do
11
+ unless relationship_link?
12
+ allow :get=>:pluck
13
+ else
14
+ allow :get=>:show, :patch=>[:prune, :graft]
15
+ end
16
+ end
17
+
18
+ app.get '', :actions=>:show do
19
+ pass unless relationship_link?
20
+
21
+ serialize_linkage
22
+ end
23
+
11
24
  app.get '', :actions=>:pluck do
12
25
  serialize_model(*pluck)
13
26
  end
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ require 'active_support/inflector'
3
+ require 'set'
2
4
  require 'sinatra/base'
3
5
  require 'sinatra/namespace'
4
6
 
7
+ require 'sinja/helpers/nested'
5
8
  require 'sinja/helpers/relationships'
6
9
  require 'sinja/relationship_routes/has_many'
7
10
  require 'sinja/relationship_routes/has_one'
@@ -9,36 +12,36 @@ require 'sinja/resource_routes'
9
12
 
10
13
  module Sinja
11
14
  module Resource
12
- def def_action_helper(action, context=nil)
13
- abort "JSONAPI resource actions can't be HTTP verbs!" \
15
+ SIDELOAD_ACTIONS = Set.new(%i[graft merge clear]).freeze
16
+
17
+ def def_action_helper(action, context)
18
+ abort "JSONAPI action helpers can't be HTTP verbs!" \
14
19
  if Sinatra::Base.respond_to?(action)
15
20
 
16
21
  context.define_singleton_method(action) do |**opts, &block|
17
- can(action, opts[:roles]) if opts.key?(:roles)
22
+ resource_roles.merge!(action=>opts[:roles]) if opts.key?(:roles)
23
+ resource_sideload.merge!(action=>opts[:sideload_on]) if opts.key?(:sideload_on)
24
+
25
+ return unless block ||=
26
+ case !method_defined?(action) && action
27
+ when :show
28
+ proc { |id| find(id) } if method_defined?(:find)
29
+ end
18
30
 
19
- return if block.nil?
31
+ # TODO: Move this to a constant or configurable?
32
+ required_arity = {
33
+ :create=>2,
34
+ :index=>-1,
35
+ :fetch=>-1
36
+ }.freeze[action] || 1
20
37
 
21
38
  define_method(action) do |*args|
22
- send("before_#{action}") if respond_to?("before_#{action}")
23
-
24
- result =
25
- begin
26
- instance_exec(*args.take(block.arity.abs), &block)
27
- rescue Exception=>e
28
- halt 409, e.message if settings._sinja.conflict?(action, e.class)
29
- #halt 422, resource.errors if settings._sinja.invalid?(action, e.class) # TODO
30
- #not_found if settings._sinja.not_found?(action, e.class) # TODO
31
- raise
32
- end
39
+ raise ArgumentError, "Unexpected block signature for `#{action}' action helper" \
40
+ unless args.length == block.arity
33
41
 
34
- # TODO: Move this to a constant or configurable?
35
- required_arity = {
36
- :create=>2,
37
- :index=>-1,
38
- :fetch=>-1
39
- }.freeze[action] || 1
42
+ public_send("before_#{action}", *args) if respond_to?("before_#{action}")
40
43
 
41
- case result
44
+ case result = instance_exec(*args, &block)
42
45
  when Array
43
46
  opts = {}
44
47
  if Hash === result.last
@@ -59,7 +62,7 @@ module Sinja
59
62
  end
60
63
 
61
64
  define_singleton_method("remove_#{action}") do
62
- remove_method(action)
65
+ remove_method(action) if respond_to?(action)
63
66
  end
64
67
  end
65
68
  end
@@ -71,18 +74,6 @@ module Sinja
71
74
  def self.registered(app)
72
75
  app.helpers Helpers::Relationships do
73
76
  attr_accessor :resource
74
-
75
- def attributes
76
- dedasherize_names(data.fetch(:attributes, {}))
77
- end
78
-
79
- def sanity_check!(id=nil)
80
- halt 409, 'Resource type in payload does not match endpoint' \
81
- if data[:type] != request.path.split('/').last # TODO
82
-
83
- halt 409, 'Resource ID in payload does not match endpoint' \
84
- if id && data[:id].to_s != id.to_s
85
- end
86
77
  end
87
78
 
88
79
  app.register ResourceRoutes
@@ -90,38 +81,28 @@ module Sinja
90
81
 
91
82
  %i[has_one has_many].each do |rel_type|
92
83
  define_method(rel_type) do |rel, &block|
93
- rel_path = rel.to_s.tr('_', '-')
84
+ rel_path = rel.to_s
85
+ .send(rel_type == :has_one ? :singularize : :pluralize)
86
+ .dasherize
87
+ .to_sym
94
88
 
95
- namespace %r{/(?<resource_id>[^/]+)(?<r>/relationships)?/#{rel_path}}, :actions=>:show do
96
- helpers do
97
- def relationship_link?
98
- !params[:r].nil?
99
- end
89
+ _resource_roles[rel_type][rel.to_sym] # trigger default proc
100
90
 
101
- def resource
102
- super || self.resource = show(params[:resource_id]).first
103
- end
91
+ namespace %r{/[^/]+(?<r>/relationships)?/#{rel_path}} do
92
+ define_singleton_method(:resource_roles) do
93
+ _resource_roles[rel_type][rel.to_sym]
94
+ end
104
95
 
105
- def sanity_check!
106
- super(params[:resource_id])
96
+ helpers Helpers::Nested do
97
+ define_method(:can?) do |*args|
98
+ super(*args, rel_type, rel.to_sym)
107
99
  end
108
100
 
109
- define_method(:linkage) do
110
- # TODO: This is extremely wasteful. Refactor JAS to expose the linkage serializer?
111
- serialize_model(resource, :include=>rel_path)['data']['relationships'][rel_path]
101
+ define_method(:serialize_linkage) do |*args|
102
+ super(resource, rel_path, *args)
112
103
  end
113
104
  end
114
105
 
115
- before do
116
- not_found 'Parent resource not found' unless resource
117
- end
118
-
119
- get '' do
120
- pass unless relationship_link?
121
-
122
- serialize_linkage
123
- end
124
-
125
106
  register RelationshipRoutes.const_get \
126
107
  rel_type.to_s.split('_').map(&:capitalize).join.to_sym
127
108
 
@@ -2,45 +2,57 @@
2
2
  module Sinja
3
3
  module ResourceRoutes
4
4
  ACTIONS = %i[index show create update destroy].freeze
5
- CONFLICT_ACTIONS = %i[create update].freeze
6
5
 
7
6
  def self.registered(app)
8
7
  app.def_action_helpers(ACTIONS, app)
9
8
 
9
+ app.head '', :pfilters=>:id do
10
+ allow :get=>:show
11
+ end
12
+
10
13
  app.get '', :pfilters=>:id, :actions=>:show do
11
14
  ids = params['filter'].delete('id')
12
15
  ids = ids.split(',') if ids.respond_to?(:split)
13
16
 
14
17
  opts = {}
15
18
  resources = [*ids].tap(&:uniq!).map! do |id|
16
- self.resource, opts = show(id)
17
- not_found "Resource '#{id}' not found" unless resource
18
- resource
19
+ tmp, opts = show(id)
20
+ raise NotFoundError, "Resource '#{id}' not found" unless tmp
21
+ tmp
19
22
  end
20
23
 
21
24
  # TODO: Serialize collection with opts from last model found?
22
25
  serialize_models(resources, opts)
23
26
  end
24
27
 
25
- app.get '', :actions=>:index do
26
- serialize_models(*index)
28
+ app.head '' do
29
+ allow :get=>:index, :post=>:create
27
30
  end
28
31
 
29
- app.get '/:id', :actions=>:show do |id|
30
- self.resource, opts = show(id)
31
- not_found "Resource '#{id}' not found" unless resource
32
- serialize_model(resource, opts)
32
+ app.get '', :actions=>:index do
33
+ serialize_models(*index)
33
34
  end
34
35
 
35
36
  app.post '', :actions=>:create do
36
37
  sanity_check!
37
- halt 403, 'Client-generated IDs not supported' \
38
- if data[:id] && method(:create).arity != 2
39
38
 
40
- _, self.resource, opts = transaction do
41
- create(attributes, data[:id]).tap do |id, *|
42
- dispatch_relationship_requests!(id, :method=>:patch)
43
- end
39
+ opts = {}
40
+ transaction do
41
+ id, self.resource, opts =
42
+ begin
43
+ args = [attributes]
44
+ args << data[:id] if data.key?(:id)
45
+ create(*args)
46
+ rescue ArgumentError
47
+ if data.key?(:id)
48
+ raise ForbiddenError, 'Client-generated ID not supported'
49
+ else
50
+ raise ForbiddenError, 'Client-generated ID not provided'
51
+ end
52
+ end
53
+
54
+ dispatch_relationship_requests!(id, :from=>:create, :methods=>{ :has_many=>:post })
55
+ validate! if respond_to?(:validate!)
44
56
  end
45
57
 
46
58
  if resource
@@ -49,27 +61,35 @@ module Sinja
49
61
  headers 'Location'=>self_link
50
62
  end
51
63
  [201, content]
52
- elsif data[:id]
64
+ elsif data.key?(:id)
53
65
  204
54
66
  else
55
67
  raise ActionHelperError, "Unexpected return value(s) from `create' action helper"
56
68
  end
57
69
  end
58
70
 
59
- app.patch '/:id', :actions=>%i[show update] do |id|
71
+ app.head '/:id' do
72
+ allow :get=>:show, :patch=>:update, :delete=>:destroy
73
+ end
74
+
75
+ app.get '/:id', :actions=>:show do |id|
76
+ tmp, opts = show(id)
77
+ raise NotFoundError, "Resource '#{id}' not found" unless tmp
78
+ serialize_model(tmp, opts)
79
+ end
80
+
81
+ app.patch '/:id', :actions=>:update do |id|
60
82
  sanity_check!(id)
61
- self.resource, = show(id)
62
- not_found "Resource '#{id}' not found" unless resource
63
- serialize_model?(transaction do
83
+ tmp, opts = transaction do
64
84
  update(attributes).tap do
65
- dispatch_relationship_requests!(id, :method=>:patch)
85
+ dispatch_relationship_requests!(id, :from=>:update)
86
+ validate! if respond_to?(:validate!)
66
87
  end
67
- end)
88
+ end
89
+ serialize_model?(tmp, opts)
68
90
  end
69
91
 
70
- app.delete '/:id', :actions=>%i[show destroy] do |id|
71
- self.resource, = show(id)
72
- not_found "Resource '#{id}' not found" unless resource
92
+ app.delete '/:id', :actions=>:destroy do |id|
73
93
  _, opts = destroy
74
94
  serialize_model?(nil, opts)
75
95
  end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  module Sinja
3
- VERSION = '0.2.0.beta2'.freeze
3
+ VERSION = '1.0.0.pre1'
4
4
  end
@@ -18,13 +18,24 @@ Gem::Specification.new do |spec|
18
18
  end
19
19
  spec.require_paths = %w[lib]
20
20
 
21
- # TODO: relax these dependencies
22
- spec.add_dependency 'json', '~> 2.0.1'
23
- spec.add_dependency 'jsonapi-serializers', '~> 0.16.0'
24
- spec.add_dependency 'sinatra', '~> 2.0.0.beta2'
25
- spec.add_dependency 'sinatra-contrib', '~> 2.0.0.beta2'
21
+ spec.required_ruby_version = '>= 2.3.0'
26
22
 
27
- spec.add_development_dependency 'bundler', '~> 1.13'
23
+ spec.add_dependency 'activesupport', ">= #{ENV.fetch('rails', '4.2.7.1')}", '< 6'
24
+ spec.add_dependency 'json', '>= 1.8.3', '< 3'
25
+ spec.add_dependency 'jsonapi-serializers', '~> 0.16'
26
+ spec.add_dependency 'mustermann', '>= 1.0.0.beta2', '< 2'
27
+ spec.add_dependency 'sinatra', ">= #{ENV.fetch('sinatra', '1.4.7')}", '< 3'
28
+ spec.add_dependency 'sinatra-contrib', ">= #{ENV.fetch('sinatra', '1.4.7')}", '< 3'
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.11'
31
+ spec.add_development_dependency 'minitest', '~> 5.9'
32
+ spec.add_development_dependency 'minitest-hooks', '~> 1.4'
33
+ #spec.add_development_dependency 'munson', '~> 0.4'
28
34
  spec.add_development_dependency 'rake', '~> 11.3'
29
- spec.add_development_dependency 'rspec', '~> 3.0'
35
+ spec.add_development_dependency 'sequel', '~> 4.38'
36
+ if defined?(JRUBY_VERSION)
37
+ spec.add_development_dependency 'jdbc-sqlite3', '~> 3.8'
38
+ else
39
+ spec.add_development_dependency 'sqlite3', '~> 1.3'
40
+ end
30
41
  end
metadata CHANGED
@@ -1,85 +1,171 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinja
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.beta2
4
+ version: 1.0.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Pastore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-20 00:00:00.000000000 Z
11
+ date: 2016-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.7.1
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.2.7.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: json
15
35
  requirement: !ruby/object:Gem::Requirement
16
36
  requirements:
17
- - - "~>"
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.8.3
40
+ - - "<"
18
41
  - !ruby/object:Gem::Version
19
- version: 2.0.1
42
+ version: '3'
20
43
  type: :runtime
21
44
  prerelease: false
22
45
  version_requirements: !ruby/object:Gem::Requirement
23
46
  requirements:
24
- - - "~>"
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.8.3
50
+ - - "<"
25
51
  - !ruby/object:Gem::Version
26
- version: 2.0.1
52
+ version: '3'
27
53
  - !ruby/object:Gem::Dependency
28
54
  name: jsonapi-serializers
29
55
  requirement: !ruby/object:Gem::Requirement
30
56
  requirements:
31
57
  - - "~>"
32
58
  - !ruby/object:Gem::Version
33
- version: 0.16.0
59
+ version: '0.16'
34
60
  type: :runtime
35
61
  prerelease: false
36
62
  version_requirements: !ruby/object:Gem::Requirement
37
63
  requirements:
38
64
  - - "~>"
39
65
  - !ruby/object:Gem::Version
40
- version: 0.16.0
66
+ version: '0.16'
67
+ - !ruby/object:Gem::Dependency
68
+ name: mustermann
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.0.0.beta2
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '2'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 1.0.0.beta2
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: '2'
41
87
  - !ruby/object:Gem::Dependency
42
88
  name: sinatra
43
89
  requirement: !ruby/object:Gem::Requirement
44
90
  requirements:
45
- - - "~>"
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.4.7
94
+ - - "<"
46
95
  - !ruby/object:Gem::Version
47
- version: 2.0.0.beta2
96
+ version: '3'
48
97
  type: :runtime
49
98
  prerelease: false
50
99
  version_requirements: !ruby/object:Gem::Requirement
51
100
  requirements:
52
- - - "~>"
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.4.7
104
+ - - "<"
53
105
  - !ruby/object:Gem::Version
54
- version: 2.0.0.beta2
106
+ version: '3'
55
107
  - !ruby/object:Gem::Dependency
56
108
  name: sinatra-contrib
57
109
  requirement: !ruby/object:Gem::Requirement
58
110
  requirements:
59
- - - "~>"
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 1.4.7
114
+ - - "<"
60
115
  - !ruby/object:Gem::Version
61
- version: 2.0.0.beta2
116
+ version: '3'
62
117
  type: :runtime
63
118
  prerelease: false
64
119
  version_requirements: !ruby/object:Gem::Requirement
65
120
  requirements:
66
- - - "~>"
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 1.4.7
124
+ - - "<"
67
125
  - !ruby/object:Gem::Version
68
- version: 2.0.0.beta2
126
+ version: '3'
69
127
  - !ruby/object:Gem::Dependency
70
128
  name: bundler
71
129
  requirement: !ruby/object:Gem::Requirement
72
130
  requirements:
73
131
  - - "~>"
74
132
  - !ruby/object:Gem::Version
75
- version: '1.13'
133
+ version: '1.11'
76
134
  type: :development
77
135
  prerelease: false
78
136
  version_requirements: !ruby/object:Gem::Requirement
79
137
  requirements:
80
138
  - - "~>"
81
139
  - !ruby/object:Gem::Version
82
- version: '1.13'
140
+ version: '1.11'
141
+ - !ruby/object:Gem::Dependency
142
+ name: minitest
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - "~>"
146
+ - !ruby/object:Gem::Version
147
+ version: '5.9'
148
+ type: :development
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - "~>"
153
+ - !ruby/object:Gem::Version
154
+ version: '5.9'
155
+ - !ruby/object:Gem::Dependency
156
+ name: minitest-hooks
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: '1.4'
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: '1.4'
83
169
  - !ruby/object:Gem::Dependency
84
170
  name: rake
85
171
  requirement: !ruby/object:Gem::Requirement
@@ -95,19 +181,33 @@ dependencies:
95
181
  - !ruby/object:Gem::Version
96
182
  version: '11.3'
97
183
  - !ruby/object:Gem::Dependency
98
- name: rspec
184
+ name: sequel
185
+ requirement: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '4.38'
190
+ type: :development
191
+ prerelease: false
192
+ version_requirements: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - "~>"
195
+ - !ruby/object:Gem::Version
196
+ version: '4.38'
197
+ - !ruby/object:Gem::Dependency
198
+ name: sqlite3
99
199
  requirement: !ruby/object:Gem::Requirement
100
200
  requirements:
101
201
  - - "~>"
102
202
  - !ruby/object:Gem::Version
103
- version: '3.0'
203
+ version: '1.3'
104
204
  type: :development
105
205
  prerelease: false
106
206
  version_requirements: !ruby/object:Gem::Requirement
107
207
  requirements:
108
208
  - - "~>"
109
209
  - !ruby/object:Gem::Version
110
- version: '3.0'
210
+ version: '1.3'
111
211
  description:
112
212
  email:
113
213
  - mike@oobak.org
@@ -124,16 +224,28 @@ files:
124
224
  - Rakefile
125
225
  - bin/console
126
226
  - bin/setup
127
- - lib/role_list.rb
227
+ - demo-app/Gemfile
228
+ - demo-app/app.rb
229
+ - demo-app/base.rb
230
+ - demo-app/boot.rb
231
+ - demo-app/classes/author.rb
232
+ - demo-app/classes/comment.rb
233
+ - demo-app/classes/post.rb
234
+ - demo-app/classes/tag.rb
235
+ - demo-app/database.rb
236
+ - demo-app/test.rb
128
237
  - lib/sinatra/jsonapi.rb
129
238
  - lib/sinja.rb
130
239
  - lib/sinja/config.rb
240
+ - lib/sinja/errors.rb
241
+ - lib/sinja/extensions/sequel.rb
242
+ - lib/sinja/helpers/nested.rb
131
243
  - lib/sinja/helpers/relationships.rb
132
244
  - lib/sinja/helpers/sequel.rb
133
245
  - lib/sinja/helpers/serializers.rb
246
+ - lib/sinja/method_override.rb
134
247
  - lib/sinja/relationship_routes/has_many.rb
135
248
  - lib/sinja/relationship_routes/has_one.rb
136
- - lib/sinja/relationship_routes/sequel.rb
137
249
  - lib/sinja/resource.rb
138
250
  - lib/sinja/resource_routes.rb
139
251
  - lib/sinja/version.rb
@@ -150,7 +262,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
262
  requirements:
151
263
  - - ">="
152
264
  - !ruby/object:Gem::Version
153
- version: '0'
265
+ version: 2.3.0
154
266
  required_rubygems_version: !ruby/object:Gem::Requirement
155
267
  requirements:
156
268
  - - ">"
@@ -158,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
270
  version: 1.3.1
159
271
  requirements: []
160
272
  rubyforge_project:
161
- rubygems_version: 2.5.1
273
+ rubygems_version: 2.5.2
162
274
  signing_key:
163
275
  specification_version: 4
164
276
  summary: RESTful, JSON:API-compliant web services in Sinatra