azeroth 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b05d8bcf76fadc6b48d87c98c5523a21e5cdb68857d0ba42d99e5e2b1c3ec41b
4
- data.tar.gz: f3e65b23e171f6c63ae143bb2a47aa7100a11ee29fdde85dd7938d5ba2a62408
3
+ metadata.gz: bcc284d1b166fec28f03e31cd42642ad09a86c85a81718ba401531443b1bbc08
4
+ data.tar.gz: 335851aa5d9a160cf387971e904248c2f89041594ccdaec57fa9ab130624558f
5
5
  SHA512:
6
- metadata.gz: 1807ceb2a7450f2d469d9232d3c3fb36ebcb7b8942b1309a7ba8686a30bebc1074598b649820d94553be4917ce15aeb2b0a919b7f2eb1a4e361bd159a50751fa
7
- data.tar.gz: 76992063fb6218ef13ebbf38416b8165b7f79bb69bb1f56330dc0c5d66cb8186394509e8b52fa7aa4c3d6f950db031692139f315cd126aa2c44b1c57ab511894
6
+ metadata.gz: 7ef7afcbd3282d181339fa6f154d1b4dcb6c6bad00f7c4e33e5c0b912b55eecc7de9876e44d2d54e7709a006a7cef487ee6c057dc0645bc0e336ff2b70629fdf
7
+ data.tar.gz: d37ba6ffdfe83b55fd51f103fd9ba3f35a3edf5eb0121c5aab424da29ffcce3e7850d52acdb4c41097c773d2f5b56692dc5f0e6c751ebce1651153bde42f2e1d
data/.circleci/config.yml CHANGED
@@ -22,7 +22,7 @@ workflows:
22
22
  jobs:
23
23
  test:
24
24
  docker:
25
- - image: darthjee/circleci_rails_gems:1.0.0
25
+ - image: darthjee/circleci_rails_gems:1.1.0
26
26
  environment:
27
27
  PROJECT: azeroth
28
28
  steps:
@@ -41,7 +41,7 @@ jobs:
41
41
  command: cc-test-reporter after-build --exit-code $?
42
42
  checks:
43
43
  docker:
44
- - image: darthjee/circleci_rails_gems:1.0.0
44
+ - image: darthjee/circleci_rails_gems:1.1.0
45
45
  environment:
46
46
  PROJECT: azeroth
47
47
  steps:
@@ -66,7 +66,7 @@ jobs:
66
66
  command: check_specs
67
67
  build-and-release:
68
68
  docker:
69
- - image: darthjee/circleci_rails_gems:1.0.0
69
+ - image: darthjee/circleci_rails_gems:1.1.0
70
70
  environment:
71
71
  PROJECT: azeroth
72
72
  steps:
data/Dockerfile CHANGED
@@ -1,12 +1,14 @@
1
- FROM darthjee/rails_gems:1.0.0 as base
2
- FROM darthjee/scripts:0.1.8 as scripts
1
+ FROM darthjee/scripts:0.3.1 as scripts
2
+
3
+ FROM darthjee/rails_gems:1.1.0 as base
4
+
5
+ COPY --chown=app:app ./ /home/app/app/
3
6
 
4
7
  ######################################
5
8
 
6
9
  FROM base as builder
7
10
 
8
- COPY --chown=app ./ /home/app/app/
9
- COPY --chown=app:app --from=scripts /home/scripts/builder/bundle_builder.sh /usr/local/sbin/
11
+ COPY --chown=app:app --from=scripts /home/scripts/builder/bundle_builder.sh /usr/local/sbin/bundle_builder.sh
10
12
 
11
13
  ENV HOME_DIR /home/app
12
14
  RUN bundle_builder.sh
@@ -14,11 +16,6 @@ RUN bundle_builder.sh
14
16
  #######################
15
17
  #FINAL IMAGE
16
18
  FROM base
17
- RUN mkdir lib/azeroth -p
18
19
 
19
20
  COPY --chown=app:app --from=builder /home/app/bundle/ /usr/local/bundle/
20
-
21
- COPY --chown=app ./*.gemspec ./Gemfile /home/app/app/
22
- COPY --chown=app ./lib/azeroth/version.rb /home/app/app/lib/azeroth/
23
-
24
21
  RUN bundle install
data/README.md CHANGED
@@ -11,7 +11,7 @@ Azeroth
11
11
 
12
12
  Yard Documentation
13
13
  -------------------
14
- [https://www.rubydoc.info/gems/azeroth/0.10.0](https://www.rubydoc.info/gems/azeroth/0.10.0)
14
+ [https://www.rubydoc.info/gems/azeroth/0.10.1](https://www.rubydoc.info/gems/azeroth/0.10.1)
15
15
 
16
16
  Azeroth has been designed making the coding of controllers easier
17
17
  as routes in controllers are usually copy, paste and replace of same
@@ -172,6 +172,35 @@ defining which and how fields will be exposed
172
172
  end
173
173
  ```
174
174
 
175
+ ```ruby
176
+ class PaginatedDocumentsController < ApplicationController
177
+ include Azeroth::Resourceable
178
+
179
+ resource_for :document, only: 'index', paginated: true
180
+ end
181
+
182
+ 30.times { create(:document) }
183
+
184
+ get '/paginated_documents.json'
185
+
186
+ # returns Array with 20 first documents
187
+ # returns in the headers pagination headers
188
+ {
189
+ 'pages' => 2,
190
+ 'per_page' => 20,
191
+ 'page' => 1
192
+ }
193
+
194
+ get '/paginated_documents.json?page=2'
195
+
196
+ # returns Array with 10 next documents
197
+ # returns in the headers pagination headers
198
+ {
199
+ 'pages' => 2,
200
+ 'per_page' => 20,
201
+ 'page' => 2
202
+ }
203
+ ```
175
204
  Exposing is done through the class method
176
205
  [expose](https://www.rubydoc.info/gems/azeroth/Azeroth/Decorator#expose-class_method)
177
206
  which accepts several options:
data/azeroth.gemspec CHANGED
@@ -20,19 +20,19 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.add_runtime_dependency 'activesupport', '~> 5.2.x'
22
22
  gem.add_runtime_dependency 'darthjee-active_ext', '>= 1.3.2'
23
- gem.add_runtime_dependency 'jace', '>= 0.0.3'
23
+ gem.add_runtime_dependency 'jace', '>= 0.1.1'
24
24
  gem.add_runtime_dependency 'sinclair', '>= 1.6.7'
25
25
 
26
- gem.add_development_dependency 'actionpack', '~> 5.2.x'
27
- gem.add_development_dependency 'activerecord', '~> 5.2.x'
26
+ gem.add_development_dependency 'actionpack', '5.2.8.1'
27
+ gem.add_development_dependency 'activerecord', '5.2.8.1'
28
28
  gem.add_development_dependency 'bundler', '~> 2.3.14'
29
29
  gem.add_development_dependency 'factory_bot', '6.2.1'
30
- gem.add_development_dependency 'minitest', '~> 5.15.0'
30
+ gem.add_development_dependency 'minitest', '5.16.2'
31
31
  gem.add_development_dependency 'nokogiri', '1.13.6'
32
32
  gem.add_development_dependency 'pry', '0.14.1'
33
33
  gem.add_development_dependency 'pry-nav', '1.0.0'
34
- gem.add_development_dependency 'rails', '~> 5.2.x'
35
- gem.add_development_dependency 'rails-controller-testing', '1.0.4'
34
+ gem.add_development_dependency 'rails', '5.2.8.1'
35
+ gem.add_development_dependency 'rails-controller-testing', '1.0.5'
36
36
  gem.add_development_dependency 'rake', '13.0.6'
37
37
  gem.add_development_dependency 'reek', '6.0.3'
38
38
  gem.add_development_dependency 'rspec', '3.11.0'
@@ -44,7 +44,7 @@ Gem::Specification.new do |gem|
44
44
  gem.add_development_dependency 'rspec-support', '3.11.0'
45
45
  gem.add_development_dependency 'rubocop', '0.80.1'
46
46
  gem.add_development_dependency 'rubocop-rspec', '1.38.1'
47
- gem.add_development_dependency 'rubycritic', '4.6.1'
47
+ gem.add_development_dependency 'rubycritic', '4.7.0'
48
48
  gem.add_development_dependency 'shoulda-matchers', '4.3.0'
49
49
  gem.add_development_dependency 'simplecov', '0.21.2'
50
50
  gem.add_development_dependency 'sqlite3', '1.4.2'
data/config/yardstick.yml CHANGED
@@ -31,6 +31,7 @@ rules:
31
31
  - Azeroth::Exception::InvalidOptions#initialize
32
32
  - Azeroth::Model#initialize
33
33
  - Azeroth::Options#initialize
34
+ - Azeroth::ParamsBuilder#initialize
34
35
  - Azeroth::RequestHandler#initialize
35
36
  - Azeroth::ResourceBuilder#initialize
36
37
  - Azeroth::ResourceRouteBuilder#initialize
data/docker-compose.yml CHANGED
@@ -21,11 +21,3 @@ services:
21
21
  <<: *base
22
22
  depends_on: [base_build]
23
23
  command: /bin/bash -c 'rspec && yard && rake yardstick_measure && rake verify_measurements'
24
-
25
- circleci:
26
- image: azeroth_circleci
27
- build:
28
- context: ./
29
- dockerfile: Dockerfile.circleci
30
- volumes:
31
- - .:/home/circleci/project
@@ -35,18 +35,13 @@ module Azeroth
35
35
  [only].flatten.map(&:to_sym) - [except].flatten.map(&:to_sym)
36
36
  end
37
37
 
38
- # Returns event dispatcher
39
- #
40
- # Event dispatcher is responsible for
41
- # sending events such as +before_save+
42
- # to it's correct calling point
43
- #
44
- # @return [Jace::Dispatcher]
45
- def event_dispatcher(event)
46
- Jace::Dispatcher.new(
47
- before: try("before_#{event}"),
48
- after: try("after_#{event}")
49
- )
38
+ # Returns the event registry
39
+ #
40
+ # Event registry is used to handle events within the request
41
+ #
42
+ # @return [Jace::Registry]
43
+ def event_registry
44
+ @event_registry ||= build_event_registry
50
45
  end
51
46
 
52
47
  alias paginated? paginated
@@ -131,5 +126,22 @@ module Azeroth
131
126
  # Number of elements when pagination is active
132
127
  #
133
128
  # @return [Integer]
129
+
130
+ private
131
+
132
+ # private
133
+ #
134
+ # Builds the event registr
135
+ #
136
+ # The event registry is build using the before
137
+ # and after actions defined in optionsy
138
+ #
139
+ # @return [Jace::Registry]
140
+ def build_event_registry
141
+ Jace::Registry.new.tap do |registry|
142
+ registry.register(:save, :after, &after_save)
143
+ registry.register(:save, :before, &before_save)
144
+ end
145
+ end
134
146
  end
135
147
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Azeroth
4
+ # @api private
5
+ # @author Darthjee
6
+ #
7
+ # Class responsible for adding params handling methods to a controller
8
+ class ParamsBuilder
9
+ # @param model [Model] resource interface
10
+ # @param builder [Sinclair] methods builder
11
+ def initialize(model, builder)
12
+ @model = model
13
+ @builder = builder
14
+ end
15
+
16
+ # Append the params methods to be built
17
+ #
18
+ # @return [Array<Sinclair::MethodDefinition>]
19
+ def append
20
+ method_name = name
21
+ allowed_attributes = permitted_attributes.map(&:to_sym)
22
+
23
+ add_method("#{name}_id") { params.require(:id) }
24
+ add_method("#{name}_params") do
25
+ params.require(method_name)
26
+ .permit(*allowed_attributes)
27
+ end
28
+ end
29
+
30
+ attr_reader :model, :builder
31
+ # @method model
32
+ # @api private
33
+ # @private
34
+ #
35
+ # Resource interface
36
+ #
37
+ # @return [Model]
38
+
39
+ # @method builder
40
+ # @api private
41
+ # @private
42
+ #
43
+ # Methods builder
44
+ #
45
+ # @return [Sinclair]
46
+
47
+ delegate :add_method, to: :builder
48
+ # @method add_method
49
+ # @api private
50
+ # @private
51
+ #
52
+ # Appends a method
53
+ #
54
+ # @return [Array<Sinclair::MethodDefinition>]
55
+
56
+ delegate :name, :klass, to: :model
57
+ # @method name
58
+ # @api private
59
+ # @private
60
+ #
61
+ # Resource name
62
+ #
63
+ # @return [Symbol,String]
64
+
65
+ # @method klass
66
+ # @api private
67
+ # @private
68
+ #
69
+ # Controller to be changed
70
+ #
71
+ # @return [Array<Sinclair::MethodDefinition>]
72
+
73
+ # Returns all updatable attributes
74
+ #
75
+ # @return [Array<String>]
76
+ def permitted_attributes
77
+ @permitted_attributes ||= klass.attribute_names - ['id']
78
+ end
79
+ end
80
+ end
@@ -36,7 +36,9 @@ module Azeroth
36
36
 
37
37
  # @private
38
38
  #
39
- # Update the resource, either by running update_with
39
+ # Update the resource
40
+ #
41
+ # This update happens by either by running update_with
40
42
  # or directly updating the attributes in the object
41
43
  #
42
44
  # @return [Object] updated resource
@@ -119,8 +119,7 @@ module Azeroth
119
119
  #
120
120
  # @return [Object] Result of given block
121
121
  def trigger_event(event, &block)
122
- options.event_dispatcher(event)
123
- .dispatch(controller, &block)
122
+ options.event_registry.trigger(event, controller, &block)
124
123
  end
125
124
 
126
125
  # @private
@@ -71,7 +71,7 @@ module Azeroth
71
71
  #
72
72
  # @return [Array<Sinclair::MethodDefinition>]
73
73
 
74
- delegate :name, :klass, to: :model
74
+ delegate :name, to: :model
75
75
  # @method name
76
76
  # @api private
77
77
  # @private
@@ -80,14 +80,6 @@ module Azeroth
80
80
  #
81
81
  # @return [Symbol,String]
82
82
 
83
- # @method klass
84
- # @api private
85
- # @private
86
- #
87
- # Controller to be changed
88
- #
89
- # @return [Array<Sinclair::MethodDefinition>]
90
-
91
83
  # @api private
92
84
  # @private
93
85
  #
@@ -104,14 +96,7 @@ module Azeroth
104
96
  #
105
97
  # @return [Array<Sinclair::MethodDefinition>]
106
98
  def add_params
107
- add_method("#{name}_id", 'params.require(:id)')
108
- add_method(
109
- "#{name}_params",
110
- <<-CODE
111
- params.require(:#{name})
112
- .permit(:#{permitted_attributes.join(', :')})
113
- CODE
114
- )
99
+ ParamsBuilder.new(model, builder).append
115
100
  end
116
101
 
117
102
  # Add methods for resource fetching
@@ -135,13 +120,6 @@ module Azeroth
135
120
  clazz.public_send(:helper_method, model.name)
136
121
  clazz.public_send(:helper_method, model.plural)
137
122
  end
138
-
139
- # Returns all updatable attributes
140
- #
141
- # @return [Array<String>]
142
- def permitted_attributes
143
- @permitted_attributes ||= klass.attribute_names - ['id']
144
- end
145
123
  end
146
124
  end
147
125
  end
@@ -14,136 +14,7 @@ module Azeroth
14
14
  # @return (see Resourceable.resource_for)
15
15
  #
16
16
  # @see (see Resourceable.resource_for)
17
- #
18
- # @example Controller without delete
19
- # class DocumentsController < ApplicationController
20
- # include Azeroth::Resourceable
21
- #
22
- # resource_for :document, except: :delete
23
- # end
24
- #
25
- # @example Controller with only create, show and list
26
- # class DocumentsController < ApplicationController
27
- # include Azeroth::Resourceable
28
- #
29
- # resource_for :document, only: %w[create index show]
30
- # end
31
- #
32
- # @example complete example gmaes and publishers
33
- # class PublishersController < ApplicationController
34
- # include Azeroth::Resourceable
35
- # skip_before_action :verify_authenticity_token
36
- #
37
- # resource_for :publisher, only: %i[create index]
38
- # end
39
- #
40
- # class GamesController < ApplicationController
41
- # include Azeroth::Resourceable
42
- # skip_before_action :verify_authenticity_token
43
- #
44
- # resource_for :game, except: :delete
45
- #
46
- # private
47
- #
48
- # def games
49
- # publisher.games
50
- # end
51
- #
52
- # def publisher
53
- # @publisher ||= Publisher.find(publisher_id)
54
- # end
55
- #
56
- # def publisher_id
57
- # params.require(:publisher_id)
58
- # end
59
- # end
60
- #
61
- # ActiveRecord::Schema.define do
62
- # self.verbose = false
63
- #
64
- # create_table :publishers, force: true do |t|
65
- # t.string :name
66
- # end
67
- #
68
- # create_table :games, force: true do |t|
69
- # t.string :name
70
- # t.integer :publisher_id
71
- # end
72
- # end
73
- #
74
- # class Publisher < ActiveRecord::Base
75
- # has_many :games
76
- # end
77
- #
78
- # class Game < ActiveRecord::Base
79
- # belongs_to :publisher
80
- # end
81
- #
82
- # class Game::Decorator < Azeroth::Decorator
83
- # expose :id
84
- # expose :name
85
- # expose :publisher, decorator: NameDecorator
86
- # end
87
- #
88
- # @example requesting games and publishers
89
- # post "/publishers.json", params: {
90
- # publisher: {
91
- # name: 'Nintendo'
92
- # }
93
- # }
94
- #
95
- # publisher = JSON.parse(response.body)
96
- # # returns
97
- # # {
98
- # # 'id' => 11,
99
- # # 'name' => 'Nintendo'
100
- # # }
101
- #
102
- # publisher = Publisher.last
103
- # post "/publishers/#{publisher['id']}/games.json", params: {
104
- # game: {
105
- # name: 'Pokemon'
106
- # }
107
- # }
108
- #
109
- # game = Game.last
110
- #
111
- # JSON.parse(response.body)
112
- # # returns
113
- # # {
114
- # # id: game.id,
115
- # # name: 'Pokemon',
116
- # # publisher: {
117
- # # name: 'Nintendo'
118
- # # }
119
- # }
120
- #
121
- # @example Controller with before_save
122
- # class PokemonsController < ApplicationController
123
- # include Azeroth::Resourceable
124
- #
125
- # resource_for :pokemon,
126
- # only: %i[create update],
127
- # before_save: :set_favorite
128
- #
129
- # private
130
- #
131
- # def set_favorite
132
- # pokemon.favorite = true
133
- # end
134
- #
135
- # def pokemons
136
- # master.pokemons
137
- # end
138
- #
139
- # def master
140
- # @master ||= PokemonMaster.find(master_id)
141
- # end
142
- #
143
- # def master_id
144
- # params.require(:pokemon_master_id)
145
- # end
146
- # end
17
+ # @example (see Resourceable.resource_for)
147
18
  def resource_for(name, **options)
148
19
  Builder.new(
149
20
  self, name, Azeroth::Options.new(options)
@@ -8,8 +8,6 @@ module Azeroth
8
8
  #
9
9
  # Concern for building controller methods for the routes
10
10
  #
11
- # @example (see Resourceable::ClassMethods#resource_for)
12
- #
13
11
  # @see Resourceable::ClassMethods
14
12
  module Resourceable
15
13
  extend ActiveSupport::Concern
@@ -27,21 +25,190 @@ module Azeroth
27
25
  #
28
26
  # @param name [String, Symbol] Name of the resource
29
27
  # @param options [Hash] resource building options
30
- # @option options only [Array<Symbol,String>] List of
28
+ # @option options only [Array<Symbol,String>,Symbol,String] List of
31
29
  # actions to be built
32
- # @option options except [Array<Symbol,String>] List of
30
+ # @option options except [Array<Symbol,String>,Symbol,String] List of
33
31
  # actions to not to be built
34
32
  # @option options decorator [Azeroth::Decorator,TrueClass,FalseClass]
35
33
  # Decorator class or flag allowing/disallowing decorators
36
34
  # @option options before_save [Symbol,Proc] method/block
37
35
  # to be ran on the controller before saving the resource
36
+ # @option options after_save [Symbol,Proc] method/block
37
+ # to be ran on the controller after saving the resource
38
38
  # @option options build_with [Symbol,Proc] method/block
39
39
  # to be ran when building resource
40
40
  # (default proc { <resource_collection>.build(resource_params) }
41
+ # @option options update_with [Symbol,Proc] method/block
42
+ # to be ran when updating resource
43
+ # (default proc { <resource>.update(resource_params) }
44
+ # @option options paginated [TrueClass,FalseClass] flag defining if index
45
+ # endpoint should be paginated
46
+ # @option options per_page [Integer] number of entries returned per
47
+ # page on index
41
48
  #
42
49
  # @return [Array<MethodDefinition>] list of methods created
43
50
  #
44
51
  # @see Options::DEFAULT_OPTIONS
52
+ #
53
+ # @example Controller without delete
54
+ # class DocumentsController < ApplicationController
55
+ # include Azeroth::Resourceable
56
+ #
57
+ # resource_for :document, except: :delete
58
+ # end
59
+ #
60
+ # @example Controller with only create, show and list
61
+ # class DocumentsController < ApplicationController
62
+ # include Azeroth::Resourceable
63
+ #
64
+ # resource_for :document, only: %w[create index show]
65
+ # end
66
+ #
67
+ # @example complete example gmaes and publishers
68
+ # class PublishersController < ApplicationController
69
+ # include Azeroth::Resourceable
70
+ # skip_before_action :verify_authenticity_token
71
+ #
72
+ # resource_for :publisher, only: %i[create index]
73
+ # end
74
+ #
75
+ # class GamesController < ApplicationController
76
+ # include Azeroth::Resourceable
77
+ # skip_before_action :verify_authenticity_token
78
+ #
79
+ # resource_for :game, except: :delete
80
+ #
81
+ # private
82
+ #
83
+ # def games
84
+ # publisher.games
85
+ # end
86
+ #
87
+ # def publisher
88
+ # @publisher ||= Publisher.find(publisher_id)
89
+ # end
90
+ #
91
+ # def publisher_id
92
+ # params.require(:publisher_id)
93
+ # end
94
+ # end
95
+ #
96
+ # ActiveRecord::Schema.define do
97
+ # self.verbose = false
98
+ #
99
+ # create_table :publishers, force: true do |t|
100
+ # t.string :name
101
+ # end
102
+ #
103
+ # create_table :games, force: true do |t|
104
+ # t.string :name
105
+ # t.integer :publisher_id
106
+ # end
107
+ # end
108
+ #
109
+ # class Publisher < ActiveRecord::Base
110
+ # has_many :games
111
+ # end
112
+ #
113
+ # class Game < ActiveRecord::Base
114
+ # belongs_to :publisher
115
+ # end
116
+ #
117
+ # class Game::Decorator < Azeroth::Decorator
118
+ # expose :id
119
+ # expose :name
120
+ # expose :publisher, decorator: NameDecorator
121
+ # end
122
+ #
123
+ # @example requesting games and publishers
124
+ # post "/publishers.json", params: {
125
+ # publisher: {
126
+ # name: 'Nintendo'
127
+ # }
128
+ # }
129
+ #
130
+ # publisher = JSON.parse(response.body)
131
+ # # returns
132
+ # # {
133
+ # # 'id' => 11,
134
+ # # 'name' => 'Nintendo'
135
+ # # }
136
+ #
137
+ # publisher = Publisher.last
138
+ # post "/publishers/#{publisher['id']}/games.json", params: {
139
+ # game: {
140
+ # name: 'Pokemon'
141
+ # }
142
+ # }
143
+ #
144
+ # game = Game.last
145
+ #
146
+ # JSON.parse(response.body)
147
+ # # returns
148
+ # # {
149
+ # # id: game.id,
150
+ # # name: 'Pokemon',
151
+ # # publisher: {
152
+ # # name: 'Nintendo'
153
+ # # }
154
+ # # }
155
+ #
156
+ # @example Controller with before_save
157
+ # class PokemonsController < ApplicationController
158
+ # include Azeroth::Resourceable
159
+ #
160
+ # resource_for :pokemon,
161
+ # only: %i[create update],
162
+ # before_save: :set_favorite
163
+ #
164
+ # private
165
+ #
166
+ # def set_favorite
167
+ # pokemon.favorite = true
168
+ # end
169
+ #
170
+ # def pokemons
171
+ # master.pokemons
172
+ # end
173
+ #
174
+ # def master
175
+ # @master ||= PokemonMaster.find(master_id)
176
+ # end
177
+ #
178
+ # def master_id
179
+ # params.require(:pokemon_master_id)
180
+ # end
181
+ # end
182
+ #
183
+ # @example Controller with paginated index response
184
+ #
185
+ # class PaginatedDocumentsController < ApplicationController
186
+ # include Azeroth::Resourceable
187
+ #
188
+ # resource_for :document, only: 'index', paginated: true
189
+ # end
190
+ #
191
+ # 30.times { create(:document) }
192
+ #
193
+ # get '/paginated_documents.json'
194
+ #
195
+ # # returns Array with 20 first documents
196
+ # # returns in the headers pagination headers
197
+ # {
198
+ # 'pages' => 2,
199
+ # 'per_page' => 20,
200
+ # 'page' => 1
201
+ # }
202
+ #
203
+ # get '/paginated_documents.json?page=2'
204
+ #
205
+ # # returns Array with 10 next documents
206
+ # # returns in the headers pagination headers
207
+ # {
208
+ # 'pages' => 2,
209
+ # 'per_page' => 20,
210
+ # 'page' => 2
211
+ # }
45
212
  end
46
213
 
47
214
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Azeroth
4
- VERSION = '0.10.0'
4
+ VERSION = '0.10.1'
5
5
  end
data/lib/azeroth.rb CHANGED
@@ -15,6 +15,7 @@ module Azeroth
15
15
  autoload :Decorator, 'azeroth/decorator'
16
16
  autoload :DummyDecorator, 'azeroth/dummy_decorator'
17
17
  autoload :Model, 'azeroth/model'
18
+ autoload :ParamsBuilder, 'azeroth/params_builder'
18
19
  autoload :RequestHandler, 'azeroth/request_handler'
19
20
  autoload :Resourceable, 'azeroth/resourceable'
20
21
  autoload :ResourceBuilder, 'azeroth/resource_builder'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Movie
4
+ class SimpleDecorator < Azeroth::Decorator
5
+ expose :name
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Movie < ActiveRecord::Base
4
+ validates :name, :director, presence: true
5
+ end
@@ -47,5 +47,10 @@ ActiveRecord::Schema.define do
47
47
  t.index %i[pokemon_master_id favorite], unique: true
48
48
  end
49
49
 
50
+ create_table :movies, force: true do |t|
51
+ t.string :name, null: false
52
+ t.string :director, null: false
53
+ end
54
+
50
55
  add_foreign_key 'pokemons', 'pokemon_masters'
51
56
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PaginatedDocumentsController, controller: true do
6
+ describe 'yard' do
7
+ describe 'GET index' do
8
+ before { create_list(:document, 30) }
9
+
10
+ it 'list documents with pagination page' do
11
+ get '/paginated_documents.json'
12
+
13
+ documents = JSON.parse(response.body)
14
+ expect(documents)
15
+ .to have(20).items
16
+
17
+ expect(response.headers['pages']).to eq(2)
18
+ expect(response.headers['per_page']).to eq(20)
19
+ expect(response.headers['page']).to eq(1)
20
+
21
+ get '/paginated_documents.json?page=2'
22
+
23
+ documents = JSON.parse(response.body)
24
+ expect(documents)
25
+ .to have(10).items
26
+
27
+ expect(response.headers['pages']).to eq(2)
28
+ expect(response.headers['per_page']).to eq(20)
29
+ expect(response.headers['page']).to eq(2)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Azeroth::ParamsBuilder do
6
+ subject(:params_builder) { described_class.new(model, builder) }
7
+
8
+ let(:model) { Azeroth::Model.new(:document, options) }
9
+ let(:options) { Azeroth::Options.new }
10
+ let(:builder) { Sinclair.new(klass) }
11
+ let(:klass) { Class.new(ParamsBuilderController) }
12
+
13
+ before do
14
+ params_builder.append
15
+ end
16
+
17
+ describe '#append' do
18
+ it 'adds id method' do
19
+ expect { builder.build }
20
+ .to add_method(:document_id).to(klass)
21
+ end
22
+
23
+ it 'adds params method' do
24
+ expect { builder.build }
25
+ .to add_method(:document_params).to(klass)
26
+ end
27
+
28
+ describe 'after the build' do
29
+ let(:controller) { klass.new(id, attributes) }
30
+ let(:document) { create(:document) }
31
+ let(:attributes) { document.attributes }
32
+ let(:id) { Random.rand(10..100) }
33
+ let(:expected_attributes) do
34
+ {
35
+ 'name' => document.name,
36
+ 'reference' => document.reference
37
+ }
38
+ end
39
+
40
+ before { builder.build }
41
+
42
+ context 'when requesting id' do
43
+ it 'returns id from request path' do
44
+ expect(controller.document_id).to eq(id)
45
+ end
46
+ end
47
+
48
+ context 'when requesting params' do
49
+ it 'returns payload' do
50
+ expect(controller.document_params.to_h)
51
+ .to eq(expected_attributes)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Azeroth::Resourceable do
6
+ let(:controller_class) do
7
+ Class.new(Controller) do
8
+ include Azeroth::Resourceable
9
+ end
10
+ end
11
+
12
+ describe '.resource_for' do
13
+ let(:params) { { id: model.id, format: :json } }
14
+ let(:model_name) { :document }
15
+ let(:model) { create(model_name) }
16
+ let(:controller) { controller_class.new(params) }
17
+ let(:decorator) { Document::Decorator }
18
+
19
+ context 'when no special option is given' do
20
+ %i[index show new edit update destroy].each do |method_name|
21
+ it do
22
+ expect { controller_class.resource_for(model_name) }
23
+ .to add_method(method_name).to(controller_class)
24
+ end
25
+ end
26
+ end
27
+
28
+ context 'when passing the only option' do
29
+ let(:options) { { only: %i[index show] } }
30
+
31
+ %i[index show].each do |method_name|
32
+ it do
33
+ expect { controller_class.resource_for(model_name, **options) }
34
+ .to add_method(method_name).to(controller_class)
35
+ end
36
+ end
37
+
38
+ %i[new edit update destroy].each do |method_name|
39
+ it do
40
+ expect { controller_class.resource_for(model_name, **options) }
41
+ .not_to add_method(method_name).to(controller_class)
42
+ end
43
+ end
44
+ end
45
+
46
+ context 'when passing the except option' do
47
+ let(:options) { { except: %i[index show] } }
48
+
49
+ %i[index show].each do |method_name|
50
+ it do
51
+ expect { controller_class.resource_for(model_name, **options) }
52
+ .not_to add_method(method_name).to(controller_class)
53
+ end
54
+ end
55
+
56
+ %i[new edit update destroy].each do |method_name|
57
+ it do
58
+ expect { controller_class.resource_for(model_name, **options) }
59
+ .to add_method(method_name).to(controller_class)
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when passing decorator option' do
65
+ let(:model_name) { :movie }
66
+ let(:decorator) { Movie::SimpleDecorator }
67
+ let(:rendered) { {} }
68
+
69
+ before do
70
+ controller_class.resource_for(model_name, decorator: decorator)
71
+
72
+ allow(controller).to receive(:render) do |args|
73
+ rendered.merge!(args[:json])
74
+ end
75
+ end
76
+
77
+ it 'decorates the model' do
78
+ controller.show
79
+ expect(rendered).to eq(decorator.new(model).as_json)
80
+ end
81
+ end
82
+
83
+ context 'when the method is called' do
84
+ let(:rendered) { {} }
85
+
86
+ before do
87
+ controller_class.resource_for(model_name)
88
+ allow(controller).to receive(:render) do |args|
89
+ rendered.merge!(args[:json])
90
+ end
91
+ end
92
+
93
+ it 'decorates the model' do
94
+ controller.show
95
+ expect(rendered).to eq(decorator.new(model).as_json)
96
+ end
97
+
98
+ context 'when the model does not have a decorator' do
99
+ let(:model_name) { :movie }
100
+
101
+ it 'renders model as json' do
102
+ controller.show
103
+ expect(rendered).to eq(model.as_json)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'action_controller'
4
4
 
5
- class Controller
5
+ class Controller < ActionController::Base
6
6
  def initialize(params = {})
7
7
  @params = ActionController::Parameters.new(params)
8
8
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ParamsBuilderController
4
+ def initialize(id, attributes)
5
+ @params = ActionController::Parameters.new(
6
+ id: id,
7
+ document: attributes
8
+ )
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :params
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :movie, class: '::Movie' do
5
+ sequence(:name) { |n| "Name-#{n}" }
6
+ sequence(:director) { |n| "Director-#{n}" }
7
+ end
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: azeroth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darthjee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-03 00:00:00.000000000 Z
11
+ date: 2022-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.0.3
47
+ version: 0.1.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.0.3
54
+ version: 0.1.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sinclair
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -70,30 +70,30 @@ dependencies:
70
70
  name: actionpack
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 5.2.x
75
+ version: 5.2.8.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 5.2.x
82
+ version: 5.2.8.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activerecord
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 5.2.x
89
+ version: 5.2.8.1
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 5.2.x
96
+ version: 5.2.8.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -126,16 +126,16 @@ dependencies:
126
126
  name: minitest
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - '='
130
130
  - !ruby/object:Gem::Version
131
- version: 5.15.0
131
+ version: 5.16.2
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - '='
137
137
  - !ruby/object:Gem::Version
138
- version: 5.15.0
138
+ version: 5.16.2
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: nokogiri
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -182,30 +182,30 @@ dependencies:
182
182
  name: rails
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - "~>"
185
+ - - '='
186
186
  - !ruby/object:Gem::Version
187
- version: 5.2.x
187
+ version: 5.2.8.1
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - "~>"
192
+ - - '='
193
193
  - !ruby/object:Gem::Version
194
- version: 5.2.x
194
+ version: 5.2.8.1
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: rails-controller-testing
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - '='
200
200
  - !ruby/object:Gem::Version
201
- version: 1.0.4
201
+ version: 1.0.5
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - '='
207
207
  - !ruby/object:Gem::Version
208
- version: 1.0.4
208
+ version: 1.0.5
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: rake
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -366,14 +366,14 @@ dependencies:
366
366
  requirements:
367
367
  - - '='
368
368
  - !ruby/object:Gem::Version
369
- version: 4.6.1
369
+ version: 4.7.0
370
370
  type: :development
371
371
  prerelease: false
372
372
  version_requirements: !ruby/object:Gem::Requirement
373
373
  requirements:
374
374
  - - '='
375
375
  - !ruby/object:Gem::Version
376
- version: 4.6.1
376
+ version: 4.7.0
377
377
  - !ruby/object:Gem::Dependency
378
378
  name: shoulda-matchers
379
379
  requirement: !ruby/object:Gem::Requirement
@@ -471,7 +471,6 @@ files:
471
471
  - ".rubocop.yml"
472
472
  - ".rubocop_todo.yml"
473
473
  - Dockerfile
474
- - Dockerfile.circleci
475
474
  - Gemfile
476
475
  - LICENSE
477
476
  - README.md
@@ -494,6 +493,7 @@ files:
494
493
  - lib/azeroth/dummy_decorator.rb
495
494
  - lib/azeroth/model.rb
496
495
  - lib/azeroth/options.rb
496
+ - lib/azeroth/params_builder.rb
497
497
  - lib/azeroth/request_handler.rb
498
498
  - lib/azeroth/request_handler/create.rb
499
499
  - lib/azeroth/request_handler/destroy.rb
@@ -551,6 +551,8 @@ files:
551
551
  - spec/dummy/app/models/game.rb
552
552
  - spec/dummy/app/models/game/decorator.rb
553
553
  - spec/dummy/app/models/id_decorator.rb
554
+ - spec/dummy/app/models/movie.rb
555
+ - spec/dummy/app/models/movie/simple_decorator.rb
554
556
  - spec/dummy/app/models/name_decorator.rb
555
557
  - spec/dummy/app/models/pokemon.rb
556
558
  - spec/dummy/app/models/pokemon/decorator.rb
@@ -617,6 +619,7 @@ files:
617
619
  - spec/integration/readme/controllers/games_controller_spec.rb
618
620
  - spec/integration/yard/azeroth/decorator_spec.rb
619
621
  - spec/integration/yard/controllers/games_controller_spec.rb
622
+ - spec/integration/yard/controllers/paginated_documents_controller_spec.rb
620
623
  - spec/lib/azeroth/controller_interface_spec.rb
621
624
  - spec/lib/azeroth/decorator/hash_builder_spec.rb
622
625
  - spec/lib/azeroth/decorator/key_value_extractor_spec.rb
@@ -625,6 +628,7 @@ files:
625
628
  - spec/lib/azeroth/dummy_decorator_spec.rb
626
629
  - spec/lib/azeroth/model_spec.rb
627
630
  - spec/lib/azeroth/options_spec.rb
631
+ - spec/lib/azeroth/params_builder_spec.rb
628
632
  - spec/lib/azeroth/request_handler/create_spec.rb
629
633
  - spec/lib/azeroth/request_handler/destroy_spec.rb
630
634
  - spec/lib/azeroth/request_handler/edit_spec.rb
@@ -635,9 +639,11 @@ files:
635
639
  - spec/lib/azeroth/request_handler_spec.rb
636
640
  - spec/lib/azeroth/resource_builder_spec.rb
637
641
  - spec/lib/azeroth/resourceable/builder_spec.rb
642
+ - spec/lib/azeroth/resourceable_spec.rb
638
643
  - spec/lib/azeroth/routes_builder_spec.rb
639
644
  - spec/spec_helper.rb
640
645
  - spec/support/app/controllers/controller.rb
646
+ - spec/support/app/controllers/params_builder_controller.rb
641
647
  - spec/support/app/controllers/request_handler_controller.rb
642
648
  - spec/support/app/controllers/resource_builder_controller.rb
643
649
  - spec/support/app/controllers/resource_route_builder_controller.rb
@@ -646,6 +652,7 @@ files:
646
652
  - spec/support/factories/dummy_model.rb
647
653
  - spec/support/factories/factory.rb
648
654
  - spec/support/factories/game.rb
655
+ - spec/support/factories/movie.rb
649
656
  - spec/support/factories/pokemon.rb
650
657
  - spec/support/factories/pokemon_master.rb
651
658
  - spec/support/factories/product.rb
@@ -672,7 +679,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
672
679
  - !ruby/object:Gem::Version
673
680
  version: '0'
674
681
  requirements: []
675
- rubygems_version: 3.3.15
682
+ rubygems_version: 3.3.20
676
683
  signing_key:
677
684
  specification_version: 4
678
685
  summary: Azeroth
@@ -720,6 +727,8 @@ test_files:
720
727
  - spec/dummy/app/models/game.rb
721
728
  - spec/dummy/app/models/game/decorator.rb
722
729
  - spec/dummy/app/models/id_decorator.rb
730
+ - spec/dummy/app/models/movie.rb
731
+ - spec/dummy/app/models/movie/simple_decorator.rb
723
732
  - spec/dummy/app/models/name_decorator.rb
724
733
  - spec/dummy/app/models/pokemon.rb
725
734
  - spec/dummy/app/models/pokemon/decorator.rb
@@ -786,6 +795,7 @@ test_files:
786
795
  - spec/integration/readme/controllers/games_controller_spec.rb
787
796
  - spec/integration/yard/azeroth/decorator_spec.rb
788
797
  - spec/integration/yard/controllers/games_controller_spec.rb
798
+ - spec/integration/yard/controllers/paginated_documents_controller_spec.rb
789
799
  - spec/lib/azeroth/controller_interface_spec.rb
790
800
  - spec/lib/azeroth/decorator/hash_builder_spec.rb
791
801
  - spec/lib/azeroth/decorator/key_value_extractor_spec.rb
@@ -794,6 +804,7 @@ test_files:
794
804
  - spec/lib/azeroth/dummy_decorator_spec.rb
795
805
  - spec/lib/azeroth/model_spec.rb
796
806
  - spec/lib/azeroth/options_spec.rb
807
+ - spec/lib/azeroth/params_builder_spec.rb
797
808
  - spec/lib/azeroth/request_handler/create_spec.rb
798
809
  - spec/lib/azeroth/request_handler/destroy_spec.rb
799
810
  - spec/lib/azeroth/request_handler/edit_spec.rb
@@ -804,9 +815,11 @@ test_files:
804
815
  - spec/lib/azeroth/request_handler_spec.rb
805
816
  - spec/lib/azeroth/resource_builder_spec.rb
806
817
  - spec/lib/azeroth/resourceable/builder_spec.rb
818
+ - spec/lib/azeroth/resourceable_spec.rb
807
819
  - spec/lib/azeroth/routes_builder_spec.rb
808
820
  - spec/spec_helper.rb
809
821
  - spec/support/app/controllers/controller.rb
822
+ - spec/support/app/controllers/params_builder_controller.rb
810
823
  - spec/support/app/controllers/request_handler_controller.rb
811
824
  - spec/support/app/controllers/resource_builder_controller.rb
812
825
  - spec/support/app/controllers/resource_route_builder_controller.rb
@@ -815,6 +828,7 @@ test_files:
815
828
  - spec/support/factories/dummy_model.rb
816
829
  - spec/support/factories/factory.rb
817
830
  - spec/support/factories/game.rb
831
+ - spec/support/factories/movie.rb
818
832
  - spec/support/factories/pokemon.rb
819
833
  - spec/support/factories/pokemon_master.rb
820
834
  - spec/support/factories/product.rb
data/Dockerfile.circleci DELETED
@@ -1,5 +0,0 @@
1
- FROM darthjee/circleci_rails_gems:1.0.0 as base
2
-
3
- COPY --chown=circleci ./ /home/circleci/project/
4
-
5
- RUN bundle install