azeroth 0.10.1 → 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/.circleci/config.yml +3 -3
- data/Dockerfile +1 -1
- data/README.md +43 -30
- data/azeroth.gemspec +8 -7
- data/config/check_specs.yml +1 -0
- data/lib/azeroth/decorator/class_methods.rb +249 -0
- data/lib/azeroth/decorator/hash_builder.rb +3 -1
- data/lib/azeroth/decorator/key_value_extractor.rb +3 -8
- 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/params_builder.rb +11 -8
- 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/resource_builder.rb +9 -10
- data/lib/azeroth/resourceable/builder.rb +15 -11
- data/lib/azeroth/routes_builder.rb +8 -10
- data/lib/azeroth/version.rb +1 -1
- data/spec/controllers/documents_with_error_controller_spec.rb +3 -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/config/environments/development.rb +1 -0
- data/spec/dummy/db/schema.rb +5 -1
- data/spec/integration/yard/azeroth/decorator_spec.rb +15 -0
- data/spec/lib/azeroth/decorator/key_value_extractor_spec.rb +3 -1
- data/spec/lib/azeroth/decorator/method_builder_spec.rb +61 -2
- data/spec/lib/azeroth/decorator_spec.rb +96 -3
- data/spec/lib/azeroth/params_builder_spec.rb +3 -1
- data/spec/lib/azeroth/request_handler/pagination_spec.rb +133 -0
- data/spec/lib/azeroth/resource_builder_spec.rb +3 -1
- data/spec/lib/azeroth/routes_builder_spec.rb +3 -1
- metadata +41 -17
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
|
#
|
@@ -5,13 +5,15 @@ module Azeroth
|
|
5
5
|
# @author Darthjee
|
6
6
|
#
|
7
7
|
# Class responsible for adding params handling methods to a controller
|
8
|
-
class ParamsBuilder
|
9
|
-
#
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
class ParamsBuilder < Sinclair::Model
|
9
|
+
# @!method initialize(model:, builder:)
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# @param model [Model] Resource interface
|
13
|
+
# @param builder [Sinclair] Methods builder
|
14
|
+
#
|
15
|
+
# @return [ParamsBuilder]
|
16
|
+
initialize_with(:model, :builder, writter: false)
|
15
17
|
|
16
18
|
# Append the params methods to be built
|
17
19
|
#
|
@@ -27,7 +29,8 @@ module Azeroth
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
|
32
|
+
private
|
33
|
+
|
31
34
|
# @method model
|
32
35
|
# @api private
|
33
36
|
# @private
|
@@ -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]
|
@@ -9,13 +9,15 @@ module Azeroth
|
|
9
9
|
# The builder adds 2 methods, one for listing all
|
10
10
|
# entries of a resource, and one for fetching an specific
|
11
11
|
# entry
|
12
|
-
class ResourceBuilder
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
class ResourceBuilder < Sinclair::Model
|
13
|
+
# @!method initialize(model:, builder:)
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
# @param model [Model] Resource model interface
|
17
|
+
# @param builder [Sinclair] method builder
|
18
|
+
#
|
19
|
+
# @return [ResourceBuilder]
|
20
|
+
initialize_with(:model, :builder, writter: false)
|
19
21
|
|
20
22
|
# Append methods to be built to the builder
|
21
23
|
#
|
@@ -28,9 +30,6 @@ module Azeroth
|
|
28
30
|
add_method(name, "@#{name} ||= #{plural}.find(#{name}_id)")
|
29
31
|
end
|
30
32
|
|
31
|
-
private
|
32
|
-
|
33
|
-
attr_reader :model, :builder
|
34
33
|
# @method model
|
35
34
|
# @api private
|
36
35
|
# @private
|
@@ -13,12 +13,12 @@ module Azeroth
|
|
13
13
|
# @see ResourceRouteBuilder
|
14
14
|
# @see RoutesBuilder
|
15
15
|
class Builder
|
16
|
-
# @param
|
16
|
+
# @param klass [ActionController::Base] Controller to
|
17
17
|
# to be changed
|
18
18
|
# @param model_name [Symbol,String]
|
19
19
|
# @param options [Options]
|
20
|
-
def initialize(
|
21
|
-
@
|
20
|
+
def initialize(klass, model_name, options)
|
21
|
+
@klass = klass
|
22
22
|
@options = options
|
23
23
|
@model = Azeroth::Model.new(model_name, options)
|
24
24
|
|
@@ -30,8 +30,8 @@ module Azeroth
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
attr_reader :
|
34
|
-
# @method
|
33
|
+
attr_reader :klass, :model, :options
|
34
|
+
# @method klass
|
35
35
|
# @api private
|
36
36
|
# @private
|
37
37
|
#
|
@@ -89,36 +89,40 @@ module Azeroth
|
|
89
89
|
#
|
90
90
|
# @see https://www.rubydoc.info/gems/sinclair Sinclair
|
91
91
|
def builder
|
92
|
-
@builder ||= Sinclair.new(
|
92
|
+
@builder ||= Sinclair.new(klass)
|
93
93
|
end
|
94
94
|
|
95
95
|
# Add methods for id and parameters
|
96
96
|
#
|
97
97
|
# @return [Array<Sinclair::MethodDefinition>]
|
98
98
|
def add_params
|
99
|
-
ParamsBuilder.new(
|
99
|
+
ParamsBuilder.new(
|
100
|
+
model: model, builder: builder
|
101
|
+
).append
|
100
102
|
end
|
101
103
|
|
102
104
|
# Add methods for resource fetching
|
103
105
|
#
|
104
106
|
# @return [Array<Sinclair::MethodDefinition>]
|
105
107
|
def add_resource
|
106
|
-
ResourceBuilder.new(model, builder).append
|
108
|
+
ResourceBuilder.new(model: model, builder: builder).append
|
107
109
|
end
|
108
110
|
|
109
111
|
# Add metohods for each route
|
110
112
|
#
|
111
113
|
# @return [Array<Sinclair::MethodDefinition>]
|
112
114
|
def add_routes
|
113
|
-
RoutesBuilder.new(
|
115
|
+
RoutesBuilder.new(
|
116
|
+
model: model, builder: builder, options: options
|
117
|
+
).append
|
114
118
|
end
|
115
119
|
|
116
120
|
# Add helpers to render objects on template
|
117
121
|
#
|
118
122
|
# @return [String]
|
119
123
|
def add_helpers
|
120
|
-
|
121
|
-
|
124
|
+
klass.public_send(:helper_method, model.name)
|
125
|
+
klass.public_send(:helper_method, model.plural)
|
122
126
|
end
|
123
127
|
end
|
124
128
|
end
|
@@ -5,15 +5,14 @@ module Azeroth
|
|
5
5
|
# @author Darthjee
|
6
6
|
#
|
7
7
|
# Builder resposible for adding routes methods to the controller
|
8
|
-
class RoutesBuilder
|
9
|
-
|
10
|
-
|
11
|
-
# @
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
8
|
+
class RoutesBuilder < Sinclair::Model
|
9
|
+
initialize_with(:model, :builder, :options, writter: false)
|
10
|
+
|
11
|
+
# @method initialize(model:, builder:, options:)
|
12
|
+
# @param model [Model] resource interface
|
13
|
+
# @param builder [Sinclair] methods builder
|
14
|
+
# @param options [Option]
|
15
|
+
# @return [RoutesBuilder]
|
17
16
|
|
18
17
|
# Append the routes methods to be built
|
19
18
|
#
|
@@ -26,7 +25,6 @@ module Azeroth
|
|
26
25
|
|
27
26
|
private
|
28
27
|
|
29
|
-
attr_reader :model, :builder, :options
|
30
28
|
# @method model
|
31
29
|
# @api private
|
32
30
|
# @private
|
data/lib/azeroth/version.rb
CHANGED
@@ -128,7 +128,9 @@ describe DocumentsWithErrorController do
|
|
128
128
|
|
129
129
|
it 'returns updated document json' do
|
130
130
|
patch :update, params: parameters
|
131
|
-
|
131
|
+
|
132
|
+
expect(JSON.parse(response.body))
|
133
|
+
.to eq(JSON.parse(expected_body))
|
132
134
|
end
|
133
135
|
|
134
136
|
it do
|
@@ -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
@@ -52,5 +52,9 @@ ActiveRecord::Schema.define do
|
|
52
52
|
t.string :director, null: false
|
53
53
|
end
|
54
54
|
|
55
|
-
|
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
|
56
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
|
@@ -4,7 +4,9 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Azeroth::Decorator::KeyValueExtractor do
|
6
6
|
subject(:extractor) do
|
7
|
-
described_class.new(
|
7
|
+
described_class.new(
|
8
|
+
decorator: decorator, attribute: attribute, options: options
|
9
|
+
)
|
8
10
|
end
|
9
11
|
|
10
12
|
let(:decorator_class) { Class.new(Azeroth::Decorator) }
|