azeroth 0.10.0 → 0.10.1

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
  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