sinja 1.2.4 → 1.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 851e8f43eabf59529257a1ef2fcc7a6df84f8ea5
4
- data.tar.gz: b75968556128599080ba71d790d8b1671cbc89e6
3
+ metadata.gz: 9054bed54d4dd7bf2e166d3708c3726ba9c92d89
4
+ data.tar.gz: 1ade5511cf29f452d7f3d4555e1a153ea895c9a7
5
5
  SHA512:
6
- metadata.gz: 0ddd2782e3e63efab5bfee81ace29615708e08cc9a137ba28451724543f98ee3f2f6d59eda0444a0859ebd9f4b8ccdc26ed661ebde0cbdf9b902e97e18f8d23f
7
- data.tar.gz: 1fea65b16d22c9bbb22dc0af0ed4744308eaf5dfe217da0c054da4c57b40ae5d00a36617b06d114ae2a50b324a72ac45a4c17917bd61debed1ed812d35c5e0ef
6
+ metadata.gz: 8cf864d75cf3232f2ab1f2699ea61e02db3a7503a446b07a6d1fe38261625b911f316e8a8851b44f13b7539d39b96a537699964c516918dd9676af0c6cf98ff0
7
+ data.tar.gz: 980b31489e1efd32956b33691bf78eb6c8cd1097a76af04cec58ab03abb567f4dd0d59ee42592079de8aa224b70beb29a3e7b6f7ee7bfb56c6453d33b09c056f
@@ -6,9 +6,6 @@ rvm:
6
6
  - ruby-head
7
7
  - jruby-9.1.7.0
8
8
  - jruby-head
9
- env:
10
- - sinatra=1.4.7 rails=4.2.7.1
11
- - sinatra=2.0.0.beta2 rails=5.0.1
12
9
  jdk:
13
10
  - oraclejdk8
14
11
  before_install:
data/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![{json:api} version](https://img.shields.io/badge/%7Bjson%3Aapi%7D%20version-1.0-lightgrey.svg)][7]
14
14
  [![Chat in #sinja-rb on Gitter](https://badges.gitter.im/sinja-rb/Lobby.svg)](https://gitter.im/sinja-rb/Lobby)
15
15
 
16
- Sinja is a [Sinatra][1] [extension][10] for quickly building [RESTful][11],
16
+ Sinja is a [Sinatra 2.0][1] [extension][10] for quickly building [RESTful][11],
17
17
  [{json:api}][2]-compliant web services, leveraging the excellent
18
18
  [JSONAPI::Serializers][3] gem for payload serialization. It enhances Sinatra's
19
19
  DSL to enable resource-, relationship-, and role-centric API development, and
@@ -40,6 +40,7 @@ framework like [Rails][16]. It's lightweight, ORM-agnostic, and
40
40
  - [Configuration](#configuration)
41
41
  - [Sinatra](#sinatra)
42
42
  - [Sinja](#sinja)
43
+ - [Resources](#resources)
43
44
  - [Resource Locators](#resource-locators)
44
45
  - [Action Helpers](#action-helpers)
45
46
  - [`resource`](#resource)
@@ -63,6 +64,7 @@ framework like [Rails][16]. It's lightweight, ORM-agnostic, and
63
64
  - [Transactions](#transactions)
64
65
  - [Side-Unloading Related Resources](#side-unloading-related-resources)
65
66
  - [Side-Loading Relationships](#side-loading-relationships)
67
+ - [Deferring Relationships](#deferring-relationships)
66
68
  - [Avoiding Null Foreign Keys](#avoiding-null-foreign-keys)
67
69
  - [Coalesced Find Requests](#coalesced-find-requests)
68
70
  - [Patchless Clients](#patchless-clients)
@@ -156,6 +158,9 @@ Or install it yourself as:
156
158
  $ gem install sinja
157
159
  ```
158
160
 
161
+ Sinja is not compatible with Sinatra 1.x due to its limitations with nested
162
+ regexp-style namespaces and routes.
163
+
159
164
  ## Ol' Blue Eyes is Back
160
165
 
161
166
  The "power" so to speak of implementing this functionality as a Sinatra
@@ -341,6 +346,36 @@ FooError` and `c.serializer_opts[:meta] = { foo: 'bar' }`) until you call
341
346
  `freeze_jsonapi` to freeze the configuration store. **You should always freeze
342
347
  the store after Sinja is configured and all your resources are defined.**
343
348
 
349
+ ### Resources
350
+
351
+ Resources declared with the `resource` keyword (and relationships declared with
352
+ the `has_many` and `has_one` keywords) are dasherized and pluralized to match
353
+ the "type" property of JSONAPI::Serializers. For example, `resource :foo_bar`
354
+ would instruct Sinja to draw the appropriate routes under `/foo-bars`. Your
355
+ serializer type(s) should always match your resource (and relationship) names;
356
+ see the relevant [documentation][33] for more information.
357
+
358
+ The primary key portion of the route is extracted using a regular expression,
359
+ `\d+` by default. To use a different pattern, pass the `:pkre` resource route
360
+ option:
361
+
362
+ ```ruby
363
+ resource :foo_bar, pkre: /\d+-\d+/ do
364
+ helpers do
365
+ def find(id)
366
+ # Look up a FooBar with a composite primary key of two integers.
367
+ FooBar[id.split('-', 2).map!(&:to_i)]
368
+ end
369
+ end
370
+
371
+ # ..
372
+ end
373
+ ```
374
+
375
+ This helps Sinja (and Sinatra) disambiguate between standard {json:api} routes
376
+ used to fetch resources (e.g. `GET /foos/1`) and similarly-structured custom
377
+ routes (e.g. `GET /foos/recent`).
378
+
344
379
  ### Resource Locators
345
380
 
346
381
  Much of Sinja's advanced functionality (e.g. updating and destroying resources,
@@ -1537,7 +1572,7 @@ logic.
1537
1572
  | Feature | JR | Sinja |
1538
1573
  | :-------------- | :------------------------------- | :------------------------------------------------ |
1539
1574
  | Serializer | Built-in | [JSONAPI::Serializers][3] |
1540
- | Framework | Rails | Sinatra, but easy to mount within others |
1575
+ | Framework | Rails | Sinatra 2.0, but easy to mount within others |
1541
1576
  | Routing | ActionDispatch::Routing | Mustermann |
1542
1577
  | Caching | ActiveSupport::Cache | BYO |
1543
1578
  | ORM | ActiveRecord/ActiveModel | BYO |
@@ -1614,3 +1649,4 @@ License](http://opensource.org/licenses/MIT).
1614
1649
  [30]: https://github.com/mwpastore/sinja-sequel
1615
1650
  [31]: http://jsonapi.org/implementations/#server-libraries-ruby
1616
1651
  [32]: http://emberjs.com
1652
+ [33]: https://github.com/fotinakis/jsonapi-serializers#more-customizations
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'jdbc-sqlite3', '~> 3.8', :platform=>:jruby
4
4
  gem 'json', '~> 2.0'
5
- gem 'sequel', '~> 4.43'
5
+ gem 'sequel', '~> 4.44'
6
6
  gem 'sinatra', '>= 2.0.0.beta2', '< 3'
7
7
  gem 'sinatra-contrib', '>= 2.0.0.beta2', '< 3'
8
8
  gem 'sinja',
@@ -10,7 +10,9 @@ require_relative 'classes/comment'
10
10
  require_relative 'classes/post'
11
11
  require_relative 'classes/tag'
12
12
 
13
- # Freeze database after creating tables and loading models
13
+ Sequel::Model.finalize_associations
14
+ Sequel::Model.freeze
15
+
14
16
  DB.freeze
15
17
 
16
18
  configure :development do
@@ -34,7 +36,7 @@ end
34
36
 
35
37
  resource :authors, &AuthorController
36
38
  resource :comments, &CommentController
37
- resource :posts, &PostController
39
+ resource :posts, :pkre=>/[\w-]+/, &PostController
38
40
  resource :tags, &TagController
39
41
 
40
42
  freeze_jsonapi
@@ -55,7 +55,7 @@ AuthorController = proc do
55
55
  show
56
56
 
57
57
  show_many do |ids|
58
- Author.where(id: ids.map!(&:to_i)).all
58
+ Author.where_all(id: ids.map!(&:to_i))
59
59
  end
60
60
 
61
61
  index do
@@ -64,7 +64,7 @@ PostController = proc do
64
64
  end
65
65
 
66
66
  show_many do |slugs|
67
- next Post.where(slug: slugs.map!(&:to_s)).all, include: %i[author tags]
67
+ next Post.where_all(slug: slugs.map!(&:to_s)), include: %i[author tags]
68
68
  end
69
69
 
70
70
  index do
@@ -2,7 +2,6 @@
2
2
  require 'set'
3
3
 
4
4
  require 'active_support/inflector'
5
- require 'mustermann'
6
5
  require 'sinatra/base'
7
6
  require 'sinatra/namespace'
8
7
 
@@ -22,7 +21,6 @@ module Sinja
22
21
  .to_h.freeze
23
22
 
24
23
  def self.registered(app)
25
- app.register Mustermann if Sinatra::VERSION[/^\d+/].to_i < 2
26
24
  app.register Sinatra::Namespace
27
25
 
28
26
  app.disable :protection, :show_exceptions, :static
@@ -102,9 +100,9 @@ module Sinja
102
100
  end
103
101
  end
104
102
 
105
- # Sinatra 2.0 re-initializes `params' at namespace boundaries, but
106
- # Sinatra 1.4 does not, so we'll reference its object_id in the flag
107
- # to make sure we only re-normalize the parameters when necessary.
103
+ # Sinatra re-initializes `params' at namespace boundaries, so we'll
104
+ # reference its object_id in the flag to make sure we only re-normalize
105
+ # the parameters when necessary.
108
106
  env['sinja.normalized'] = params.object_id
109
107
  end
110
108
  end
@@ -313,7 +311,7 @@ module Sinja
313
311
  end
314
312
  end
315
313
 
316
- def resource(resource_name, konst=nil, &block)
314
+ def resource(resource_name, konst=nil, **opts, &block)
317
315
  abort "Must supply proc constant or block for `resource'" \
318
316
  unless block = (konst if konst.instance_of?(Proc)) || block
319
317
 
@@ -328,6 +326,9 @@ module Sinja
328
326
  # trigger default procs
329
327
  config = _sinja.resource_config[resource_name]
330
328
 
329
+ # incorporate route options
330
+ config[:route_opts].merge!(opts)
331
+
331
332
  namespace %r{/#{resource_name}(?![^/])} do
332
333
  define_singleton_method(:_resource_config) { config }
333
334
  define_singleton_method(:resource_config) { config[:resource] }
@@ -338,12 +339,14 @@ module Sinja
338
339
  end
339
340
  end
340
341
 
341
- before %r{/(?<id>[^/]+)(?:/.+)?} do |id|
342
+ before %r{/(#{config[:route_opts][:pkre]})(?:/.*)?} do |id|
342
343
  self.resource =
343
344
  if env.key?('sinja.resource')
344
345
  env['sinja.resource']
345
346
  elsif respond_to?(:find)
346
347
  find(id)
348
+ else
349
+ raise SinjaError, 'Resource locator not defined!'
347
350
  end
348
351
 
349
352
  raise NotFoundError, "Resource '#{id}' not found" unless resource
@@ -83,6 +83,7 @@ module Sinja
83
83
  }}.curry
84
84
 
85
85
  @resource_config = Hash.new { |h, k| h[k] = {
86
+ :route_opts=>{ :pkre=>/\d+/ },
86
87
  :resource=>Hash.new(&action_proc[:resource]),
87
88
  :has_many=>Hash.new { |rh, rk| rh[rk] = Hash.new(&action_proc[:has_many]) },
88
89
  :has_one=>Hash.new { |rh, rk| rh[rk] = Hash.new(&action_proc[:has_one]) }
@@ -36,7 +36,12 @@ module Sinja
36
36
  end
37
37
 
38
38
  def serialize_response_body
39
- JSON.send settings._sinja.json_generator, response.body
39
+ case response.content_type[/^[^;]+/]
40
+ when *[mime_type(:api_json), mime_type(:json), mime_type(:javascript)].freeze
41
+ JSON.send(settings._sinja.json_generator, response.body)
42
+ else
43
+ Array(response.body).map!(&:to_s)
44
+ end
40
45
  rescue JSON::GeneratorError
41
46
  raise BadRequestError, 'Unserializable entities in the response body'
42
47
  end
@@ -89,7 +89,7 @@ module Sinja
89
89
 
90
90
  config = _resource_config[rel_type][rel] # trigger default proc
91
91
 
92
- namespace %r{/[^/]+(?<r>/relationships)?/#{rel}(?![^/])} do
92
+ namespace %r{/#{_resource_config[:route_opts][:pkre]}(?<r>/relationships)?/#{rel}(?![^/])} do
93
93
  define_singleton_method(:resource_config) { config }
94
94
 
95
95
  helpers Helpers::Nested do
@@ -82,17 +82,19 @@ module Sinja
82
82
  end
83
83
  end
84
84
 
85
- app.options '/:id' do
85
+ pkre = app._resource_config[:route_opts][:pkre]
86
+
87
+ app.options %r{/#{pkre}} do
86
88
  allow :get=>:show, :patch=>:update, :delete=>:destroy
87
89
  end
88
90
 
89
- app.get '/:id', :qparams=>%i[include fields], :actions=>:show do |id|
91
+ app.get %r{/(#{pkre})}, :qparams=>%i[include fields], :actions=>:show do |id|
90
92
  tmp, opts = show(*[].tap { |a| a << id unless respond_to?(:find) })
91
93
  raise NotFoundError, "Resource '#{id}' not found" unless tmp
92
94
  serialize_model(tmp, opts)
93
95
  end
94
96
 
95
- app.patch '/:id', :qparams=>%i[include fields], :actions=>:update do |id|
97
+ app.patch %r{/(#{pkre})}, :qparams=>%i[include fields], :actions=>:update do |id|
96
98
  sanity_check!(id)
97
99
  tmp, opts = transaction do
98
100
  update(attributes).tap do
@@ -103,7 +105,7 @@ module Sinja
103
105
  serialize_model?(tmp, opts)
104
106
  end
105
107
 
106
- app.delete '/:id', :actions=>:destroy do |id|
108
+ app.delete %r{/#{pkre}}, :actions=>:destroy do
107
109
  _, opts = destroy
108
110
  serialize_model?(nil, opts)
109
111
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sinja
3
- VERSION = '1.2.4'
3
+ VERSION = '1.2.5'
4
4
  end
@@ -37,18 +37,18 @@ Gem::Specification.new do |spec|
37
37
 
38
38
  spec.required_ruby_version = '>= 2.3.0'
39
39
 
40
- spec.add_dependency 'activesupport', ">= #{ENV.fetch('rails', '4.2.7.1')}", '< 6'
40
+ spec.add_dependency 'activesupport', '>= 4.2.8', '< 6'
41
41
  spec.add_dependency 'json', '>= 1.8.3', '< 3'
42
- spec.add_dependency 'jsonapi-serializers', '~> 0.16'
43
- spec.add_dependency 'mustermann', '>= 1.0.0.beta2', '< 2'
44
- spec.add_dependency 'sinatra', ">= #{ENV.fetch('sinatra', '1.4.7')}", '< 3'
45
- spec.add_dependency 'sinatra-contrib', ">= #{ENV.fetch('sinatra', '1.4.7')}", '< 3'
42
+ spec.add_dependency 'jsonapi-serializers', '>= 0.16.2', '< 2'
43
+ spec.add_dependency 'sinatra', '>= 2.0.0.rc1', '< 3'
44
+ spec.add_dependency 'sinatra-contrib', '>= 2.0.0.rc1', '< 3'
46
45
 
47
46
  spec.add_development_dependency 'bundler', '~> 1.11'
48
47
  spec.add_development_dependency 'jdbc-sqlite3', '~> 3.8' if defined?(JRUBY_VERSION)
49
48
  spec.add_development_dependency 'minitest', '~> 5.9'
50
49
  spec.add_development_dependency 'minitest-hooks', '~> 1.4'
51
50
  #spec.add_development_dependency 'munson', '~> 0.4' # in Gemfile
51
+ spec.add_development_dependency 'rack-test', '~> 0.6'
52
52
  spec.add_development_dependency 'rake', '~> 12.0'
53
53
  spec.add_development_dependency 'sequel', '~> 4.41'
54
54
  #spec.add_development_dependency 'sinja-sequel', '~> 0.1' # in Gemfile
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinja
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Pastore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-13 00:00:00.000000000 Z
11
+ date: 2017-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.7.1
19
+ version: 4.2.8
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '6'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 4.2.7.1
29
+ version: 4.2.8
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6'
@@ -52,25 +52,11 @@ dependencies:
52
52
  version: '3'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: jsonapi-serializers
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: '0.16'
60
- type: :runtime
61
- prerelease: false
62
- version_requirements: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '0.16'
67
- - !ruby/object:Gem::Dependency
68
- name: mustermann
69
55
  requirement: !ruby/object:Gem::Requirement
70
56
  requirements:
71
57
  - - ">="
72
58
  - !ruby/object:Gem::Version
73
- version: 1.0.0.beta2
59
+ version: 0.16.2
74
60
  - - "<"
75
61
  - !ruby/object:Gem::Version
76
62
  version: '2'
@@ -80,7 +66,7 @@ dependencies:
80
66
  requirements:
81
67
  - - ">="
82
68
  - !ruby/object:Gem::Version
83
- version: 1.0.0.beta2
69
+ version: 0.16.2
84
70
  - - "<"
85
71
  - !ruby/object:Gem::Version
86
72
  version: '2'
@@ -90,7 +76,7 @@ dependencies:
90
76
  requirements:
91
77
  - - ">="
92
78
  - !ruby/object:Gem::Version
93
- version: 1.4.7
79
+ version: 2.0.0.rc1
94
80
  - - "<"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '3'
@@ -100,7 +86,7 @@ dependencies:
100
86
  requirements:
101
87
  - - ">="
102
88
  - !ruby/object:Gem::Version
103
- version: 1.4.7
89
+ version: 2.0.0.rc1
104
90
  - - "<"
105
91
  - !ruby/object:Gem::Version
106
92
  version: '3'
@@ -110,7 +96,7 @@ dependencies:
110
96
  requirements:
111
97
  - - ">="
112
98
  - !ruby/object:Gem::Version
113
- version: 1.4.7
99
+ version: 2.0.0.rc1
114
100
  - - "<"
115
101
  - !ruby/object:Gem::Version
116
102
  version: '3'
@@ -120,7 +106,7 @@ dependencies:
120
106
  requirements:
121
107
  - - ">="
122
108
  - !ruby/object:Gem::Version
123
- version: 1.4.7
109
+ version: 2.0.0.rc1
124
110
  - - "<"
125
111
  - !ruby/object:Gem::Version
126
112
  version: '3'
@@ -166,6 +152,20 @@ dependencies:
166
152
  - - "~>"
167
153
  - !ruby/object:Gem::Version
168
154
  version: '1.4'
155
+ - !ruby/object:Gem::Dependency
156
+ name: rack-test
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: '0.6'
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: '0.6'
169
169
  - !ruby/object:Gem::Dependency
170
170
  name: rake
171
171
  requirement: !ruby/object:Gem::Requirement