azeroth 1.0.0 → 1.1.0
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 +4 -4
- data/README.md +13 -1
- data/config/check_specs.yml +1 -0
- data/lib/azeroth/decorator/class_methods.rb +249 -0
- data/lib/azeroth/decorator/method_builder.rb +23 -7
- data/lib/azeroth/decorator/options.rb +3 -1
- data/lib/azeroth/decorator.rb +30 -188
- data/lib/azeroth/request_handler/index.rb +7 -33
- data/lib/azeroth/request_handler/pagination.rb +53 -0
- data/lib/azeroth/request_handler.rb +8 -7
- data/lib/azeroth/version.rb +1 -1
- data/spec/dummy/app/models/website/decorator.rb +11 -0
- data/spec/dummy/app/models/website/with_location.rb +21 -0
- data/spec/dummy/app/models/website.rb +4 -0
- data/spec/dummy/db/schema.rb +6 -0
- data/spec/integration/yard/azeroth/decorator_spec.rb +15 -0
- data/spec/lib/azeroth/decorator/method_builder_spec.rb +61 -2
- data/spec/lib/azeroth/decorator_spec.rb +96 -3
- data/spec/lib/azeroth/request_handler/pagination_spec.rb +133 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c8e0229917b320108b25371d2c30ca48f83663288d50d2e767b8cf45c037c95
|
4
|
+
data.tar.gz: 2e6fe774d10fa5b5ca3f22c0b4deac4828a28480ebd3ebb1cce370c84c0f359c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b517e33573aa729a94fee810f0f4cea17a39533359332017e1dea8a3d80c74aacaac1010754739d8ba312d42353c57bb93d0c172aa640453450383ea1ff99328
|
7
|
+
data.tar.gz: 7bdfbfce3bdc6f40c2c82ea904a5778b5d0e7cc037f4fbf73f2e7d5fe8a449b7dacbac41f55523afea298bea5de998cc5d442e395fbf4949e555775aeabccff4
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Azeroth
|
|
11
11
|
|
12
12
|
Yard Documentation
|
13
13
|
-------------------
|
14
|
-
[https://www.rubydoc.info/gems/azeroth/1.
|
14
|
+
[https://www.rubydoc.info/gems/azeroth/1.1.0](https://www.rubydoc.info/gems/azeroth/1.1.0)
|
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
|
@@ -25,6 +25,10 @@ does not perform database operations
|
|
25
25
|
Future versions will enable `html` rendering to also perform
|
26
26
|
database operations.
|
27
27
|
|
28
|
+
Current Release: [1.1.0](https://github.com/darthjee/azeroth/tree/1.1.0)
|
29
|
+
|
30
|
+
[Next release](https://github.com/darthjee/azeroth/compare/1.1.0...master)
|
31
|
+
|
28
32
|
Installation
|
29
33
|
---------------
|
30
34
|
|
@@ -167,6 +171,14 @@ It accepts options
|
|
167
171
|
used to define how an object is exposed as json on controller responses
|
168
172
|
defining which and how fields will be exposed
|
169
173
|
|
174
|
+
Exposing options:
|
175
|
+
|
176
|
+
- as: custom key to expose the value as
|
177
|
+
- if: method/block to be called checking if an attribute should or should not be exposed
|
178
|
+
- decorator: flag to use or not a decorator or decorator class to be used
|
179
|
+
- reader: Flag indicating if a reader to access the attribute should be created. usefull if you want method_missing to take over
|
180
|
+
- override: Flag indicating if an existing method should be overriden. This is useful when a method acessor was included from another module
|
181
|
+
|
170
182
|
```ruby
|
171
183
|
# pokemon/decorator.rb
|
172
184
|
|
data/config/check_specs.yml
CHANGED
@@ -0,0 +1,249 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Azeroth
|
4
|
+
class Decorator
|
5
|
+
# @api private
|
6
|
+
# @author Darthjee
|
7
|
+
#
|
8
|
+
# Class methods added by {Decorator}
|
9
|
+
#
|
10
|
+
# @see ClassMethods#expose
|
11
|
+
module ClassMethods
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
# All attributes exposed
|
15
|
+
#
|
16
|
+
# @return [Hash<Symbol,Hash>]
|
17
|
+
def attributes_map
|
18
|
+
@attributes_map ||= build_attributes_map
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
# @private
|
25
|
+
#
|
26
|
+
# Initialize attributes to be exposed map
|
27
|
+
#
|
28
|
+
# When the class inherity from another
|
29
|
+
# decorator, the new class should expose the
|
30
|
+
# same attributes.
|
31
|
+
#
|
32
|
+
# @return [Hash<Symbol,Hash>]
|
33
|
+
def build_attributes_map
|
34
|
+
superclass.try(:attributes_map).dup || {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# @visibility public
|
38
|
+
# @api (see Decorator.expose)
|
39
|
+
# @private
|
40
|
+
#
|
41
|
+
# Expose attributes on json decorated
|
42
|
+
#
|
43
|
+
# @param (see Decorator.expose)
|
44
|
+
# @option (see Decorator.expose)
|
45
|
+
#
|
46
|
+
# @return (see Decorator.expose)
|
47
|
+
#
|
48
|
+
# @example Simple usage
|
49
|
+
# class DummyModel
|
50
|
+
# include ActiveModel::Model
|
51
|
+
#
|
52
|
+
# attr_accessor :id, :first_name, :last_name, :age,
|
53
|
+
# :favorite_pokemon
|
54
|
+
#
|
55
|
+
# class Decorator < Azeroth::Decorator
|
56
|
+
# expose :name
|
57
|
+
# expose :age
|
58
|
+
# expose :favorite_pokemon, as: :pokemon
|
59
|
+
#
|
60
|
+
# def name
|
61
|
+
# [object.first_name, object.last_name].join(' ')
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @example With relations
|
67
|
+
# # pokemon/decorator.rb
|
68
|
+
#
|
69
|
+
# class Pokemon::Decorator < Azeroth::Decorator
|
70
|
+
# expose :name
|
71
|
+
# expose :previous_form_name, as: :evolution_of, if: :evolution?
|
72
|
+
#
|
73
|
+
# def evolution?
|
74
|
+
# previous_form
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# def previous_form_name
|
78
|
+
# previous_form.name
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# # pokemon/favorite_decorator.rb
|
83
|
+
#
|
84
|
+
# class Pokemon::FavoriteDecorator < Pokemon::Decorator
|
85
|
+
# expose :nickname
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # pokemon_master/decorator.rb
|
89
|
+
#
|
90
|
+
# class PokemonMaster < ActiveRecord::Base
|
91
|
+
# has_one :favorite_pokemon, -> { where(favorite: true) },
|
92
|
+
# class_name: 'Pokemon'
|
93
|
+
# has_many :pokemons
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# # pokemon.rb
|
97
|
+
#
|
98
|
+
# class Pokemon < ActiveRecord::Base
|
99
|
+
# belongs_to :pokemon_master
|
100
|
+
# has_one :previous_form,
|
101
|
+
# class_name: 'Pokemon',
|
102
|
+
# foreign_key: :previous_form_id
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# # pokemon_master.rb
|
106
|
+
#
|
107
|
+
# class PokemonMaster::Decorator < Azeroth::Decorator
|
108
|
+
# expose :name
|
109
|
+
# expose :age
|
110
|
+
# expose :favorite_pokemon, decorator: Pokemon::FavoriteDecorator
|
111
|
+
# expose :pokemons
|
112
|
+
#
|
113
|
+
# def name
|
114
|
+
# [
|
115
|
+
# first_name,
|
116
|
+
# last_name
|
117
|
+
# ].compact.join(' ')
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# # schema.rb
|
122
|
+
#
|
123
|
+
# ActiveRecord::Schema.define do
|
124
|
+
# self.verbose = false
|
125
|
+
#
|
126
|
+
# create_table :pokemon_masters, force: true do |t|
|
127
|
+
# t.string :first_name, null: false
|
128
|
+
# t.string :last_name
|
129
|
+
# t.integer :age, null: false
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# create_table :pokemons, force: true do |t|
|
133
|
+
# t.string :name, null: false
|
134
|
+
# t.string :nickname
|
135
|
+
# t.integer :pokemon_master_id
|
136
|
+
# t.boolean :favorite
|
137
|
+
# t.integer :previous_form_id
|
138
|
+
# t.index %i[pokemon_master_id favorite], unique: true
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# add_foreign_key 'pokemons', 'pokemon_masters'
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# # test.rb
|
145
|
+
#
|
146
|
+
# master = PokemonMaster.create(
|
147
|
+
# first_name: 'Ash',
|
148
|
+
# last_name: 'Ketchum',
|
149
|
+
# age: 10
|
150
|
+
# )
|
151
|
+
#
|
152
|
+
# master.create_favorite_pokemon(
|
153
|
+
# name: 'pikachu',
|
154
|
+
# nickname: 'Pikachu'
|
155
|
+
# )
|
156
|
+
#
|
157
|
+
# metapod = Pokemon.create(name: :metapod)
|
158
|
+
#
|
159
|
+
# master.pokemons.create(
|
160
|
+
# name: 'butterfree', previous_form: metapod
|
161
|
+
# )
|
162
|
+
# master.pokemons.create(name: 'squirtle')
|
163
|
+
#
|
164
|
+
# decorator = PokemonMaster::Decorator.new(master)
|
165
|
+
#
|
166
|
+
# decorator.as_json
|
167
|
+
# # returns
|
168
|
+
# # {
|
169
|
+
# # 'age' => 10,
|
170
|
+
# # 'name' => 'Ash Ketchum',
|
171
|
+
# # 'favorite_pokemon' => {
|
172
|
+
# # 'name' => 'pikachu',
|
173
|
+
# # 'nickname' => 'Pikachu'
|
174
|
+
# # },
|
175
|
+
# # 'pokemons' => [{
|
176
|
+
# # 'name' => 'butterfree',
|
177
|
+
# # 'evolution_of' => 'metapod'
|
178
|
+
# # }, {
|
179
|
+
# # 'name' => 'squirtle'
|
180
|
+
# # }, {
|
181
|
+
# # 'name' => 'pikachu'
|
182
|
+
# # }]
|
183
|
+
# # }
|
184
|
+
#
|
185
|
+
# @example With method building options
|
186
|
+
# ActiveRecord::Schema.define do
|
187
|
+
# self.verbose = false
|
188
|
+
#
|
189
|
+
# create_table :websites, force: true do |t|
|
190
|
+
# t.string :domain, null: false
|
191
|
+
# t.integer :port, limit: 2, unsigned: true
|
192
|
+
# t.string :protocol, limit: 5
|
193
|
+
# end
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# class Website < ActiveRecord::Base
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# class Website < ActiveRecord::Base
|
200
|
+
# module WithLocation
|
201
|
+
# def location
|
202
|
+
# "#{protocol}://#{domain}:#{port}"
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
# def protocol
|
206
|
+
# website.protocol || '*'
|
207
|
+
# end
|
208
|
+
#
|
209
|
+
# def domain
|
210
|
+
# website.domain || '*'
|
211
|
+
# end
|
212
|
+
#
|
213
|
+
# def port
|
214
|
+
# website.port || '*'
|
215
|
+
# end
|
216
|
+
# end
|
217
|
+
# end
|
218
|
+
#
|
219
|
+
# class Website < ActiveRecord::Base
|
220
|
+
# class Decorator < Azeroth::Decorator
|
221
|
+
# include WithLocation
|
222
|
+
#
|
223
|
+
# expose :location, override: false
|
224
|
+
#
|
225
|
+
# alias website object
|
226
|
+
# end
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# website = Website.create(
|
230
|
+
# protocol: :http,
|
231
|
+
# domain: 'google.com'
|
232
|
+
# )
|
233
|
+
#
|
234
|
+
# decorator = Website::Decorator.new(website)
|
235
|
+
#
|
236
|
+
# decorator.as_json
|
237
|
+
#
|
238
|
+
# # returns
|
239
|
+
# # { 'location' => 'http://google.com:*' }
|
240
|
+
def expose(attribute, **options_hash)
|
241
|
+
options = Decorator::Options.new(options_hash)
|
242
|
+
|
243
|
+
MethodBuilder.build_reader(self, attribute, options)
|
244
|
+
|
245
|
+
attributes_map[attribute] = options
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -7,20 +7,36 @@ module Azeroth
|
|
7
7
|
# Responsible for building readers for attributes
|
8
8
|
# @api private
|
9
9
|
class MethodBuilder < Sinclair
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
class << self
|
11
|
+
# Builds reader
|
12
|
+
#
|
13
|
+
# reaader delegate method calls to @object
|
14
|
+
#
|
15
|
+
# @return [Array<Sinclair::MethodDefinition>]
|
16
|
+
def build_reader(klass, attribute, options)
|
17
|
+
new(klass, options).build_reader(attribute)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(klass, options)
|
22
|
+
super(klass)
|
23
|
+
@options = options
|
17
24
|
end
|
18
25
|
|
19
26
|
# (see MethodBuilder.build_reader)
|
20
27
|
def build_reader(attribute)
|
28
|
+
return if skip_creation?(attribute)
|
29
|
+
|
21
30
|
add_method(attribute, "@object.#{attribute}")
|
22
31
|
build
|
23
32
|
end
|
33
|
+
|
34
|
+
def skip_creation?(attribute)
|
35
|
+
return true unless options.reader
|
36
|
+
return false unless klass.method_defined?(attribute)
|
37
|
+
|
38
|
+
!options.override
|
39
|
+
end
|
24
40
|
end
|
25
41
|
end
|
26
42
|
end
|
data/lib/azeroth/decorator.rb
CHANGED
@@ -40,200 +40,42 @@ module Azeroth
|
|
40
40
|
# # 'pokemon' => 'Arcanine'
|
41
41
|
# # }
|
42
42
|
class Decorator
|
43
|
+
autoload :ClassMethods, 'azeroth/decorator/class_methods'
|
43
44
|
autoload :HashBuilder, 'azeroth/decorator/hash_builder'
|
44
45
|
autoload :KeyValueExtractor, 'azeroth/decorator/key_value_extractor'
|
45
46
|
autoload :MethodBuilder, 'azeroth/decorator/method_builder'
|
46
47
|
autoload :Options, 'azeroth/decorator/options'
|
47
48
|
|
48
|
-
|
49
|
-
# @api private
|
50
|
-
#
|
51
|
-
# All attributes exposed
|
52
|
-
#
|
53
|
-
# @return [Hash<Symbol,Hash>]
|
54
|
-
def attributes_map
|
55
|
-
@attributes_map ||= build_attributes_map
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# @api private
|
61
|
-
# @private
|
62
|
-
#
|
63
|
-
# Initialize attributes to be exposed map
|
64
|
-
#
|
65
|
-
# When the class inherity from another
|
66
|
-
# decorator, the new class should expose the
|
67
|
-
# same attributes.
|
68
|
-
#
|
69
|
-
# @return [Hash<Symbol,Hash>]
|
70
|
-
def build_attributes_map
|
71
|
-
superclass.try(:attributes_map).dup || {}
|
72
|
-
end
|
73
|
-
|
74
|
-
# @visibility public
|
75
|
-
# @api public
|
76
|
-
# @private
|
77
|
-
#
|
78
|
-
# Expose attributes on json decorated
|
79
|
-
#
|
80
|
-
# @param attribute [Symbol,String] attribute to be exposed
|
81
|
-
# @param options_hash [Hash] exposing options
|
82
|
-
# @option options_hash as [Symbol,String] custom key
|
83
|
-
# to expose
|
84
|
-
# @option options_hash if [Symbol,Proc] method/block
|
85
|
-
# to be called
|
86
|
-
# checking if an attribute should or should not
|
87
|
-
# be exposed
|
88
|
-
# @option options_hash decorator [FalseClass,TrueClass,Class]
|
89
|
-
# flag to use or not a decorator or decorator class to be used
|
90
|
-
#
|
91
|
-
# @return [Array<Symbol>]
|
92
|
-
#
|
93
|
-
# @example
|
94
|
-
# class DummyModel
|
95
|
-
# include ActiveModel::Model
|
96
|
-
#
|
97
|
-
# attr_accessor :id, :first_name, :last_name, :age,
|
98
|
-
# :favorite_pokemon
|
99
|
-
#
|
100
|
-
# class Decorator < Azeroth::Decorator
|
101
|
-
# expose :name
|
102
|
-
# expose :age
|
103
|
-
# expose :favorite_pokemon, as: :pokemon
|
104
|
-
#
|
105
|
-
# def name
|
106
|
-
# [object.first_name, object.last_name].join(' ')
|
107
|
-
# end
|
108
|
-
# end
|
109
|
-
# end
|
110
|
-
#
|
111
|
-
# @example With relations
|
112
|
-
# # pokemon/decorator.rb
|
113
|
-
#
|
114
|
-
# class Pokemon::Decorator < Azeroth::Decorator
|
115
|
-
# expose :name
|
116
|
-
# expose :previous_form_name, as: :evolution_of, if: :evolution?
|
117
|
-
#
|
118
|
-
# def evolution?
|
119
|
-
# previous_form
|
120
|
-
# end
|
121
|
-
#
|
122
|
-
# def previous_form_name
|
123
|
-
# previous_form.name
|
124
|
-
# end
|
125
|
-
# end
|
126
|
-
#
|
127
|
-
# # pokemon/favorite_decorator.rb
|
128
|
-
#
|
129
|
-
# class Pokemon::FavoriteDecorator < Pokemon::Decorator
|
130
|
-
# expose :nickname
|
131
|
-
# end
|
132
|
-
#
|
133
|
-
# # pokemon_master/decorator.rb
|
134
|
-
#
|
135
|
-
# class PokemonMaster < ActiveRecord::Base
|
136
|
-
# has_one :favorite_pokemon, -> { where(favorite: true) },
|
137
|
-
# class_name: 'Pokemon'
|
138
|
-
# has_many :pokemons
|
139
|
-
# end
|
140
|
-
#
|
141
|
-
# # pokemon.rb
|
142
|
-
#
|
143
|
-
# class Pokemon < ActiveRecord::Base
|
144
|
-
# belongs_to :pokemon_master
|
145
|
-
# has_one :previous_form,
|
146
|
-
# class_name: 'Pokemon',
|
147
|
-
# foreign_key: :previous_form_id
|
148
|
-
# end
|
149
|
-
#
|
150
|
-
# # pokemon_master.rb
|
151
|
-
#
|
152
|
-
# class PokemonMaster::Decorator < Azeroth::Decorator
|
153
|
-
# expose :name
|
154
|
-
# expose :age
|
155
|
-
# expose :favorite_pokemon, decorator: Pokemon::FavoriteDecorator
|
156
|
-
# expose :pokemons
|
157
|
-
#
|
158
|
-
# def name
|
159
|
-
# [
|
160
|
-
# first_name,
|
161
|
-
# last_name
|
162
|
-
# ].compact.join(' ')
|
163
|
-
# end
|
164
|
-
# end
|
165
|
-
#
|
166
|
-
# # schema.rb
|
167
|
-
#
|
168
|
-
# ActiveRecord::Schema.define do
|
169
|
-
# self.verbose = false
|
170
|
-
#
|
171
|
-
# create_table :pokemon_masters, force: true do |t|
|
172
|
-
# t.string :first_name, null: false
|
173
|
-
# t.string :last_name
|
174
|
-
# t.integer :age, null: false
|
175
|
-
# end
|
176
|
-
#
|
177
|
-
# create_table :pokemons, force: true do |t|
|
178
|
-
# t.string :name, null: false
|
179
|
-
# t.string :nickname
|
180
|
-
# t.integer :pokemon_master_id
|
181
|
-
# t.boolean :favorite
|
182
|
-
# t.integer :previous_form_id
|
183
|
-
# t.index %i[pokemon_master_id favorite], unique: true
|
184
|
-
# end
|
185
|
-
#
|
186
|
-
# add_foreign_key 'pokemons', 'pokemon_masters'
|
187
|
-
# end
|
188
|
-
#
|
189
|
-
# # test.rb
|
190
|
-
#
|
191
|
-
# master = PokemonMaster.create(
|
192
|
-
# first_name: 'Ash',
|
193
|
-
# last_name: 'Ketchum',
|
194
|
-
# age: 10
|
195
|
-
# )
|
196
|
-
#
|
197
|
-
# master.create_favorite_pokemon(
|
198
|
-
# name: 'pikachu',
|
199
|
-
# nickname: 'Pikachu'
|
200
|
-
# )
|
201
|
-
#
|
202
|
-
# metapod = Pokemon.create(name: :metapod)
|
203
|
-
#
|
204
|
-
# master.pokemons.create(
|
205
|
-
# name: 'butterfree', previous_form: metapod
|
206
|
-
# )
|
207
|
-
# master.pokemons.create(name: 'squirtle')
|
208
|
-
#
|
209
|
-
# decorator = PokemonMaster::Decorator.new(master)
|
210
|
-
#
|
211
|
-
# decorator.as_json
|
212
|
-
# # returns
|
213
|
-
# # {
|
214
|
-
# # 'age' => 10,
|
215
|
-
# # 'name' => 'Ash Ketchum',
|
216
|
-
# # 'favorite_pokemon' => {
|
217
|
-
# # 'name' => 'pikachu',
|
218
|
-
# # 'nickname' => 'Pikachu'
|
219
|
-
# # },
|
220
|
-
# # 'pokemons' => [{
|
221
|
-
# # 'name' => 'butterfree',
|
222
|
-
# # 'evolution_of' => 'metapod'
|
223
|
-
# # }, {
|
224
|
-
# # 'name' => 'squirtle'
|
225
|
-
# # }, {
|
226
|
-
# # 'name' => 'pikachu'
|
227
|
-
# # }]
|
228
|
-
# # }
|
229
|
-
def expose(attribute, **options_hash)
|
230
|
-
options = Decorator::Options.new(options_hash)
|
49
|
+
extend ClassMethods
|
231
50
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
51
|
+
# @method self.expose(attribute, **options_hash)
|
52
|
+
# @visibility public
|
53
|
+
# @api public
|
54
|
+
# @private
|
55
|
+
#
|
56
|
+
# Expose attributes on json decorated
|
57
|
+
#
|
58
|
+
# @param attribute [Symbol,String] attribute to be exposed
|
59
|
+
# @param options_hash [Hash] exposing options
|
60
|
+
# @option options_hash as [Symbol,String] custom key
|
61
|
+
# to expose the value as
|
62
|
+
# @option options_hash if [Symbol,Proc] method/block
|
63
|
+
# to be called
|
64
|
+
# checking if an attribute should or should not
|
65
|
+
# be exposed
|
66
|
+
# @option options_hash decorator [FalseClass,TrueClass,Class]
|
67
|
+
# flag to use or not a decorator or decorator class to be used
|
68
|
+
# @option options_hash reader [Boolean] Flag indicating if a reader
|
69
|
+
# to access the attribute should be created. usefull if you want
|
70
|
+
# method_missing to take over
|
71
|
+
# @option options_hash override [Boolean] Flag indicating if an
|
72
|
+
# existing method should be overriden.
|
73
|
+
# This is useful when a method acessor was included from another module
|
74
|
+
#
|
75
|
+
# @return [Array<Symbol>]
|
76
|
+
#
|
77
|
+
# @see Decorator::ClassMethods#expose Decorator::ClassMethods#expose
|
78
|
+
# for examples
|
237
79
|
|
238
80
|
# @api private
|
239
81
|
#
|
@@ -8,7 +8,13 @@ module Azeroth
|
|
8
8
|
class Index < RequestHandler
|
9
9
|
private
|
10
10
|
|
11
|
-
delegate :
|
11
|
+
delegate :per_page, :offset, :limit,
|
12
|
+
:current_page, to: :pagination
|
13
|
+
delegate :paginated?, to: :options
|
14
|
+
|
15
|
+
def pagination
|
16
|
+
@pagination ||= Pagination.new(params, options)
|
17
|
+
end
|
12
18
|
|
13
19
|
# @private
|
14
20
|
#
|
@@ -45,29 +51,6 @@ module Azeroth
|
|
45
51
|
scoped_entries.offset(offset).limit(limit)
|
46
52
|
end
|
47
53
|
|
48
|
-
# @private
|
49
|
-
#
|
50
|
-
# offest used in pagination
|
51
|
-
#
|
52
|
-
# offset is retrieved from +params[:per_page]+
|
53
|
-
# or +options.per_page+
|
54
|
-
#
|
55
|
-
# @return [Integer]
|
56
|
-
def offset
|
57
|
-
(current_page - 1) * limit
|
58
|
-
end
|
59
|
-
|
60
|
-
# @private
|
61
|
-
#
|
62
|
-
# limit used in pagination
|
63
|
-
#
|
64
|
-
# limit is retrieved from +params[:page]+
|
65
|
-
#
|
66
|
-
# @return [Integer]
|
67
|
-
def limit
|
68
|
-
(params[:per_page] || per_page).to_i
|
69
|
-
end
|
70
|
-
|
71
54
|
# @private
|
72
55
|
#
|
73
56
|
# default scope of elements
|
@@ -77,15 +60,6 @@ module Azeroth
|
|
77
60
|
controller.send(model.plural)
|
78
61
|
end
|
79
62
|
|
80
|
-
# @private
|
81
|
-
#
|
82
|
-
# calculates current page
|
83
|
-
#
|
84
|
-
# @return [Integer]
|
85
|
-
def current_page
|
86
|
-
(params[:page] || 1).to_i
|
87
|
-
end
|
88
|
-
|
89
63
|
# @private
|
90
64
|
#
|
91
65
|
# calculates how many pages are there
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Azeroth
|
4
|
+
class RequestHandler
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
# Wrapper for request finding pagination attributes
|
8
|
+
class Pagination
|
9
|
+
def initialize(params, options)
|
10
|
+
@params = params
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
delegate :per_page, to: :options
|
15
|
+
|
16
|
+
# @private
|
17
|
+
#
|
18
|
+
# offest used in pagination
|
19
|
+
#
|
20
|
+
# offset is retrieved from +params[:per_page]+
|
21
|
+
# or +options.per_page+
|
22
|
+
#
|
23
|
+
# @return [Integer]
|
24
|
+
def offset
|
25
|
+
(current_page - 1) * limit
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
#
|
30
|
+
# limit used in pagination
|
31
|
+
#
|
32
|
+
# limit is retrieved from +params[:page]+
|
33
|
+
#
|
34
|
+
# @return [Integer]
|
35
|
+
def limit
|
36
|
+
(params[:per_page] || per_page).to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
# @private
|
40
|
+
#
|
41
|
+
# calculates current page
|
42
|
+
#
|
43
|
+
# @return [Integer]
|
44
|
+
def current_page
|
45
|
+
(params[:page] || 1).to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
attr_reader :params, :options
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -8,13 +8,14 @@ module Azeroth
|
|
8
8
|
# Request handler sends messages to the controller
|
9
9
|
# in order to get the resource and rendering the response
|
10
10
|
class RequestHandler
|
11
|
-
autoload :Create,
|
12
|
-
autoload :Destroy,
|
13
|
-
autoload :Edit,
|
14
|
-
autoload :Index,
|
15
|
-
autoload :New,
|
16
|
-
autoload :
|
17
|
-
autoload :
|
11
|
+
autoload :Create, 'azeroth/request_handler/create'
|
12
|
+
autoload :Destroy, 'azeroth/request_handler/destroy'
|
13
|
+
autoload :Edit, 'azeroth/request_handler/edit'
|
14
|
+
autoload :Index, 'azeroth/request_handler/index'
|
15
|
+
autoload :New, 'azeroth/request_handler/new'
|
16
|
+
autoload :Pagination, 'azeroth/request_handler/pagination'
|
17
|
+
autoload :Show, 'azeroth/request_handler/show'
|
18
|
+
autoload :Update, 'azeroth/request_handler/update'
|
18
19
|
|
19
20
|
# @param controller [ApplicationController]
|
20
21
|
# @param model [Azeroth::Model]
|
data/lib/azeroth/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Website < ActiveRecord::Base
|
4
|
+
module WithLocation
|
5
|
+
def location
|
6
|
+
"#{protocol}://#{domain}:#{port}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def protocol
|
10
|
+
website.protocol || '*'
|
11
|
+
end
|
12
|
+
|
13
|
+
def domain
|
14
|
+
website.domain || '*'
|
15
|
+
end
|
16
|
+
|
17
|
+
def port
|
18
|
+
website.port || '*'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -51,4 +51,10 @@ ActiveRecord::Schema.define do
|
|
51
51
|
t.string :name, null: false
|
52
52
|
t.string :director, null: false
|
53
53
|
end
|
54
|
+
|
55
|
+
create_table :websites, force: true do |t|
|
56
|
+
t.string :domain, null: false
|
57
|
+
t.integer :port, limit: 2, unsigned: true
|
58
|
+
t.string :protocol, limit: 5
|
59
|
+
end
|
54
60
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'spec_helper'
|
4
|
+
|
3
5
|
describe Azeroth::Decorator do
|
4
6
|
describe 'yard' do
|
5
7
|
describe '#as_json' do
|
@@ -60,6 +62,19 @@ describe Azeroth::Decorator do
|
|
60
62
|
}
|
61
63
|
)
|
62
64
|
end
|
65
|
+
|
66
|
+
it 'example without override' do
|
67
|
+
website = Website.create(
|
68
|
+
protocol: :http,
|
69
|
+
domain: 'google.com'
|
70
|
+
)
|
71
|
+
|
72
|
+
decorator = Website::Decorator.new(website)
|
73
|
+
|
74
|
+
expect(decorator.as_json).to eq(
|
75
|
+
'location' => 'http://google.com:*'
|
76
|
+
)
|
77
|
+
end
|
63
78
|
end
|
64
79
|
end
|
65
80
|
end
|
@@ -3,21 +3,80 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Azeroth::Decorator::MethodBuilder do
|
6
|
+
subject(:build_reader) do
|
7
|
+
described_class.build_reader(decorator_class, :age, options)
|
8
|
+
end
|
9
|
+
|
6
10
|
let(:decorator_class) { Class.new(Azeroth::Decorator) }
|
7
11
|
let(:decorator) { decorator_class.new(object) }
|
8
12
|
let(:model) { build(:dummy_model) }
|
9
13
|
let(:object) { model }
|
14
|
+
let(:options) { Azeroth::Decorator::Options.new(options_hash) }
|
15
|
+
let(:options_hash) { {} }
|
10
16
|
|
11
17
|
describe '.build_reader' do
|
12
18
|
it do
|
13
|
-
expect {
|
19
|
+
expect { build_reader }
|
14
20
|
.to add_method(:age).to(decorator)
|
15
21
|
end
|
16
22
|
|
17
23
|
it do
|
18
|
-
|
24
|
+
build_reader
|
19
25
|
|
20
26
|
expect(decorator.age).to eq(model.age)
|
21
27
|
end
|
28
|
+
|
29
|
+
context 'when passing reader option' do
|
30
|
+
context 'when passing true' do
|
31
|
+
let(:options_hash) { { reader: true } }
|
32
|
+
|
33
|
+
it do
|
34
|
+
expect { build_reader }
|
35
|
+
.to add_method(:age).to(decorator)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when passing false' do
|
40
|
+
let(:options_hash) { { reader: false } }
|
41
|
+
|
42
|
+
it do
|
43
|
+
expect { build_reader }
|
44
|
+
.not_to add_method(:age).to(decorator)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when passing override option as true' do
|
50
|
+
let(:options_hash) { { override: false } }
|
51
|
+
|
52
|
+
it do
|
53
|
+
expect { build_reader }
|
54
|
+
.to add_method(:age).to(decorator)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when method already existed' do
|
59
|
+
before do
|
60
|
+
decorator_class.define_method(:age) { 1 }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when passing override option as true' do
|
64
|
+
let(:options_hash) { { override: true } }
|
65
|
+
|
66
|
+
it do
|
67
|
+
expect { build_reader }
|
68
|
+
.to change_method(:age).on(decorator)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when passing override option as false' do
|
73
|
+
let(:options_hash) { { override: false } }
|
74
|
+
|
75
|
+
it do
|
76
|
+
expect { build_reader }
|
77
|
+
.not_to change_method(:age).on(decorator)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
22
81
|
end
|
23
82
|
end
|
@@ -5,14 +5,16 @@ require 'spec_helper'
|
|
5
5
|
describe Azeroth::Decorator do
|
6
6
|
subject(:decorator) { DummyModel::Decorator.new(object) }
|
7
7
|
|
8
|
-
let(:model)
|
9
|
-
let(:object)
|
8
|
+
let(:model) { build(:dummy_model) }
|
9
|
+
let(:object) { model }
|
10
|
+
let(:instance) { decorator.new(object) }
|
10
11
|
|
11
12
|
describe '.expose' do
|
12
13
|
subject(:decorator) { Class.new(described_class) }
|
13
14
|
|
15
|
+
let(:options_hash) { {} }
|
14
16
|
let(:expected_options) do
|
15
|
-
Azeroth::Decorator::Options.new
|
17
|
+
Azeroth::Decorator::Options.new(options_hash)
|
16
18
|
end
|
17
19
|
|
18
20
|
it do
|
@@ -59,6 +61,97 @@ describe Azeroth::Decorator do
|
|
59
61
|
.and raise_error(Sinclair::Exception::InvalidOptions)
|
60
62
|
end
|
61
63
|
end
|
64
|
+
|
65
|
+
context 'when decorator already has the method' do
|
66
|
+
before do
|
67
|
+
decorator.define_method(:name) do
|
68
|
+
'some name'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when not passing override' do
|
73
|
+
it do
|
74
|
+
expect { decorator.send(:expose, :name) }
|
75
|
+
.to change(decorator, :attributes_map)
|
76
|
+
.from({})
|
77
|
+
.to({ name: expected_options })
|
78
|
+
end
|
79
|
+
|
80
|
+
it do
|
81
|
+
expect { decorator.send(:expose, :name) }
|
82
|
+
.to change_method(:name)
|
83
|
+
.on(instance)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when passing override as true' do
|
88
|
+
let(:options_hash) { { override: true } }
|
89
|
+
|
90
|
+
it do
|
91
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
92
|
+
.to change(decorator, :attributes_map)
|
93
|
+
.from({})
|
94
|
+
.to({ name: expected_options })
|
95
|
+
end
|
96
|
+
|
97
|
+
it do
|
98
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
99
|
+
.to change_method(:name)
|
100
|
+
.on(instance)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when passing override as false' do
|
105
|
+
let(:options_hash) { { override: false } }
|
106
|
+
|
107
|
+
it do
|
108
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
109
|
+
.to change(decorator, :attributes_map)
|
110
|
+
.from({})
|
111
|
+
.to({ name: expected_options })
|
112
|
+
end
|
113
|
+
|
114
|
+
it do
|
115
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
116
|
+
.not_to change_method(:name)
|
117
|
+
.on(instance)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when passing reader option' do
|
123
|
+
context 'when option is true' do
|
124
|
+
let(:options_hash) { { reader: true } }
|
125
|
+
|
126
|
+
it do
|
127
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
128
|
+
.to change(decorator, :attributes_map)
|
129
|
+
.from({})
|
130
|
+
.to({ name: expected_options })
|
131
|
+
end
|
132
|
+
|
133
|
+
it do
|
134
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
135
|
+
.to add_method(:name).to(decorator)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when option is false' do
|
140
|
+
let(:options_hash) { { reader: false } }
|
141
|
+
|
142
|
+
it do
|
143
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
144
|
+
.to change(decorator, :attributes_map)
|
145
|
+
.from({})
|
146
|
+
.to({ name: expected_options })
|
147
|
+
end
|
148
|
+
|
149
|
+
it do
|
150
|
+
expect { decorator.send(:expose, :name, **options_hash) }
|
151
|
+
.not_to add_method(:name).to(decorator)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
62
155
|
end
|
63
156
|
|
64
157
|
describe '#as_json' do
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Azeroth::RequestHandler::Pagination do
|
6
|
+
subject(:pagination) { described_class.new(params, options) }
|
7
|
+
|
8
|
+
let(:options) { Azeroth::Options.new(options_hash) }
|
9
|
+
let(:options_hash) { {} }
|
10
|
+
let(:params) { ActionController::Parameters.new(parameters) }
|
11
|
+
let(:parameters) { {} }
|
12
|
+
|
13
|
+
describe '#offset' do
|
14
|
+
context 'when nothing was defined' do
|
15
|
+
it do
|
16
|
+
expect(pagination.offset).to be_zero
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when parameters has page value' do
|
21
|
+
let(:parameters) { { page: page } }
|
22
|
+
let(:page) { Random.rand(1..10) }
|
23
|
+
let(:expected_offset) { (page - 1) * expected_per_page }
|
24
|
+
let(:expected_per_page) { 20 }
|
25
|
+
|
26
|
+
it 'returns value from request using default per_page' do
|
27
|
+
expect(pagination.offset).to eq(expected_offset)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when parameters has per_page value' do
|
32
|
+
let(:parameters) { { per_page: per_page } }
|
33
|
+
let(:per_page) { Random.rand(1..10) }
|
34
|
+
|
35
|
+
it do
|
36
|
+
expect(pagination.offset).to be_zero
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when parameters has page and per page values' do
|
41
|
+
let(:parameters) { { page: page, per_page: per_page } }
|
42
|
+
let(:page) { Random.rand(1..10) }
|
43
|
+
let(:per_page) { Random.rand(1..10) }
|
44
|
+
let(:expected_offset) { (page - 1) * expected_per_page }
|
45
|
+
let(:expected_per_page) { per_page }
|
46
|
+
|
47
|
+
it 'returns value from request' do
|
48
|
+
expect(pagination.offset).to eq(expected_offset)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when parameters has page and options per page values' do
|
53
|
+
let(:parameters) { { page: page } }
|
54
|
+
let(:options_hash) { { per_page: per_page } }
|
55
|
+
let(:page) { Random.rand(1..10) }
|
56
|
+
let(:per_page) { Random.rand(1..10) }
|
57
|
+
let(:expected_offset) { (page - 1) * expected_per_page }
|
58
|
+
let(:expected_per_page) { per_page }
|
59
|
+
|
60
|
+
it 'returns value from request and options' do
|
61
|
+
expect(pagination.offset).to eq(expected_offset)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when params has page and per_page and options per page values' do
|
66
|
+
let(:parameters) { { page: page, per_page: per_page } }
|
67
|
+
let(:options_hash) { { per_page: options_per_page } }
|
68
|
+
let(:page) { Random.rand(1..10) }
|
69
|
+
let(:options_per_page) { Random.rand(1..10) }
|
70
|
+
let(:per_page) { Random.rand(1..10) }
|
71
|
+
let(:expected_offset) { (page - 1) * expected_per_page }
|
72
|
+
let(:expected_per_page) { per_page }
|
73
|
+
|
74
|
+
it 'returns value from request' do
|
75
|
+
expect(pagination.offset).to eq(expected_offset)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#limit' do
|
81
|
+
context 'when nothing was defined' do
|
82
|
+
it 'returns default value' do
|
83
|
+
expect(pagination.limit).to eq(20)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when parameters has per_page' do
|
88
|
+
let(:parameters) { { per_page: per_page } }
|
89
|
+
let(:per_page) { Random.rand(1..10) }
|
90
|
+
|
91
|
+
it 'returns value from request' do
|
92
|
+
expect(pagination.limit).to eq(per_page)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when options has per_page' do
|
97
|
+
let(:options_hash) { { per_page: per_page } }
|
98
|
+
let(:per_page) { Random.rand(1..10) }
|
99
|
+
|
100
|
+
it 'returns value from options' do
|
101
|
+
expect(pagination.limit).to eq(per_page)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when params and options have per_page' do
|
106
|
+
let(:parameters) { { per_page: per_page } }
|
107
|
+
let(:per_page) { Random.rand(1..10) }
|
108
|
+
let(:options_hash) { { per_page: options_per_page } }
|
109
|
+
let(:options_per_page) { Random.rand(1..10) }
|
110
|
+
|
111
|
+
it 'returns value from request' do
|
112
|
+
expect(pagination.limit).to eq(per_page)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#current_page' do
|
118
|
+
context 'when nothing was defined' do
|
119
|
+
it 'returns first page' do
|
120
|
+
expect(pagination.current_page).to eq(1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when parameters has page' do
|
125
|
+
let(:parameters) { { page: page } }
|
126
|
+
let(:page) { Random.rand(1..10) }
|
127
|
+
|
128
|
+
it 'returns value from request' do
|
129
|
+
expect(pagination.current_page).to eq(page)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
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: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darthjee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -500,6 +500,7 @@ files:
|
|
500
500
|
- lib/azeroth.rb
|
501
501
|
- lib/azeroth/controller_interface.rb
|
502
502
|
- lib/azeroth/decorator.rb
|
503
|
+
- lib/azeroth/decorator/class_methods.rb
|
503
504
|
- lib/azeroth/decorator/hash_builder.rb
|
504
505
|
- lib/azeroth/decorator/key_value_extractor.rb
|
505
506
|
- lib/azeroth/decorator/method_builder.rb
|
@@ -514,6 +515,7 @@ files:
|
|
514
515
|
- lib/azeroth/request_handler/edit.rb
|
515
516
|
- lib/azeroth/request_handler/index.rb
|
516
517
|
- lib/azeroth/request_handler/new.rb
|
518
|
+
- lib/azeroth/request_handler/pagination.rb
|
517
519
|
- lib/azeroth/request_handler/show.rb
|
518
520
|
- lib/azeroth/request_handler/update.rb
|
519
521
|
- lib/azeroth/resource_builder.rb
|
@@ -578,6 +580,9 @@ files:
|
|
578
580
|
- spec/dummy/app/models/product/decorator_with_factory.rb
|
579
581
|
- spec/dummy/app/models/publisher.rb
|
580
582
|
- spec/dummy/app/models/user.rb
|
583
|
+
- spec/dummy/app/models/website.rb
|
584
|
+
- spec/dummy/app/models/website/decorator.rb
|
585
|
+
- spec/dummy/app/models/website/with_location.rb
|
581
586
|
- spec/dummy/app/views/documents/edit.html
|
582
587
|
- spec/dummy/app/views/documents/index.html
|
583
588
|
- spec/dummy/app/views/documents/new.html
|
@@ -648,6 +653,7 @@ files:
|
|
648
653
|
- spec/lib/azeroth/request_handler/edit_spec.rb
|
649
654
|
- spec/lib/azeroth/request_handler/index_spec.rb
|
650
655
|
- spec/lib/azeroth/request_handler/new_spec.rb
|
656
|
+
- spec/lib/azeroth/request_handler/pagination_spec.rb
|
651
657
|
- spec/lib/azeroth/request_handler/show_spec.rb
|
652
658
|
- spec/lib/azeroth/request_handler/update_spec.rb
|
653
659
|
- spec/lib/azeroth/request_handler_spec.rb
|
@@ -754,6 +760,9 @@ test_files:
|
|
754
760
|
- spec/dummy/app/models/product/decorator_with_factory.rb
|
755
761
|
- spec/dummy/app/models/publisher.rb
|
756
762
|
- spec/dummy/app/models/user.rb
|
763
|
+
- spec/dummy/app/models/website.rb
|
764
|
+
- spec/dummy/app/models/website/decorator.rb
|
765
|
+
- spec/dummy/app/models/website/with_location.rb
|
757
766
|
- spec/dummy/app/views/documents/edit.html
|
758
767
|
- spec/dummy/app/views/documents/index.html
|
759
768
|
- spec/dummy/app/views/documents/new.html
|
@@ -824,6 +833,7 @@ test_files:
|
|
824
833
|
- spec/lib/azeroth/request_handler/edit_spec.rb
|
825
834
|
- spec/lib/azeroth/request_handler/index_spec.rb
|
826
835
|
- spec/lib/azeroth/request_handler/new_spec.rb
|
836
|
+
- spec/lib/azeroth/request_handler/pagination_spec.rb
|
827
837
|
- spec/lib/azeroth/request_handler/show_spec.rb
|
828
838
|
- spec/lib/azeroth/request_handler/update_spec.rb
|
829
839
|
- spec/lib/azeroth/request_handler_spec.rb
|