azeroth 0.6.3 → 0.7.2
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 +37 -2
- data/.rubocop.yml +11 -0
- data/Dockerfile +2 -2
- data/README.md +164 -1
- data/azeroth.gemspec +6 -5
- data/lib/azeroth.rb +1 -0
- data/lib/azeroth/decorator.rb +123 -0
- data/lib/azeroth/decorator/key_value_extractor.rb +2 -2
- data/lib/azeroth/decorator/options.rb +3 -3
- data/lib/azeroth/model.rb +3 -1
- data/lib/azeroth/options.rb +38 -1
- data/lib/azeroth/request_handler.rb +39 -2
- data/lib/azeroth/request_handler/create.rb +31 -5
- data/lib/azeroth/request_handler/update.rb +3 -3
- data/lib/azeroth/resourceable.rb +27 -0
- data/lib/azeroth/resourceable/class_methods.rb +120 -6
- data/lib/azeroth/routes_builder.rb +2 -1
- data/lib/azeroth/version.rb +1 -1
- data/spec/controllers/pokemon_masters_controller_spec.rb +56 -0
- data/spec/controllers/pokemons_controller_spec.rb +56 -0
- data/spec/dummy/app/controllers/games_controller.rb +22 -0
- data/spec/dummy/app/controllers/pokemon_masters_controller.rb +9 -0
- data/spec/dummy/app/controllers/pokemons_controller.rb +27 -0
- data/spec/dummy/app/controllers/publishers_controller.rb +8 -0
- data/spec/dummy/app/models/game.rb +5 -0
- data/spec/dummy/app/models/game/decorator.rb +9 -0
- data/spec/dummy/app/models/name_decorator.rb +5 -0
- data/spec/dummy/app/models/pokemon.rb +8 -0
- data/spec/dummy/app/models/pokemon/decorator.rb +16 -0
- data/spec/dummy/app/models/pokemon/favorite_decorator.rb +7 -0
- data/spec/dummy/app/models/pokemon_master.rb +7 -0
- data/spec/dummy/app/models/pokemon_master/decorator.rb +17 -0
- data/spec/dummy/app/models/publisher.rb +5 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/db/schema.rb +26 -0
- data/spec/integration/readme/azeroth/decorator_spec.rb +48 -0
- data/spec/integration/readme/controllers/games_controller_spec.rb +42 -0
- data/spec/integration/yard/azeroth/decorator_spec.rb +58 -17
- data/spec/integration/yard/controllers/games_controller_spec.rb +42 -0
- data/spec/lib/azeroth/decorator/key_value_extractor_spec.rb +32 -0
- data/spec/lib/azeroth/decorator_spec.rb +28 -2
- data/spec/lib/azeroth/request_handler/create_spec.rb +166 -0
- data/spec/lib/azeroth/request_handler/update_spec.rb +91 -0
- data/spec/lib/azeroth/request_handler_spec.rb +3 -1
- data/spec/support/app/controllers/request_handler_controller.rb +12 -1
- data/spec/support/factories/game.rb +8 -0
- data/spec/support/factories/pokemon.rb +8 -0
- data/spec/support/factories/pokemon_master.rb +9 -0
- data/spec/support/factories/publisher.rb +7 -0
- data/spec/support/shared_examples/request_handler.rb +5 -2
- metadata +70 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbddea8e78679a5a20ccb7c04fd94da0f55718713add9d352d97bff07921df9c
|
4
|
+
data.tar.gz: e5cc1161a4b36df822458101ce8e4f443a8be05eaf5a0430a0ae09db313e8794
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd4a272074e69969eddf5d7c3fa3b96d1b0154e117d81b6be419b59573169e100773ecbd97d96f2465a72a5c5e0458c3d7e13d12b5e2c1ed710412a8139e7b4c
|
7
|
+
data.tar.gz: 0eb07f9c6da10355a9c9db82e555d0eecfaefa75abce57603109efa8aa841a53a70f372afeef6dafe5df9e88504a4180e76f66a8060cbf5841dbdeb6895f6a9f
|
data/.circleci/config.yml
CHANGED
@@ -1,8 +1,24 @@
|
|
1
1
|
version: 2
|
2
|
+
workflows:
|
3
|
+
version: 2
|
4
|
+
test-and-build:
|
5
|
+
jobs:
|
6
|
+
- test:
|
7
|
+
filters:
|
8
|
+
tags:
|
9
|
+
only: /.*/
|
10
|
+
- build-and-release:
|
11
|
+
requires: [test]
|
12
|
+
filters:
|
13
|
+
tags:
|
14
|
+
only: /\d+\.\d+\.\d+/
|
15
|
+
branches:
|
16
|
+
only:
|
17
|
+
- master
|
2
18
|
jobs:
|
3
|
-
|
19
|
+
test:
|
4
20
|
docker:
|
5
|
-
- image: darthjee/circleci_rails_gems:0.5.
|
21
|
+
- image: darthjee/circleci_rails_gems:0.5.4
|
6
22
|
environment:
|
7
23
|
PROJECT: azeroth
|
8
24
|
steps:
|
@@ -34,3 +50,22 @@ jobs:
|
|
34
50
|
- run:
|
35
51
|
name: Check unit tests
|
36
52
|
command: check_specs
|
53
|
+
build-and-release:
|
54
|
+
docker:
|
55
|
+
- image: darthjee/circleci_rails_gems:0.5.4
|
56
|
+
environment:
|
57
|
+
PROJECT: azeroth
|
58
|
+
steps:
|
59
|
+
- checkout
|
60
|
+
- run:
|
61
|
+
name: Bundle Install
|
62
|
+
command: bundle install
|
63
|
+
- run:
|
64
|
+
name: Signin
|
65
|
+
command: build_gem.sh signin
|
66
|
+
- run:
|
67
|
+
name: Build Gem
|
68
|
+
command: build_gem.sh build
|
69
|
+
- run:
|
70
|
+
name: Push Gem
|
71
|
+
command: build_gem.sh push
|
data/.rubocop.yml
CHANGED
@@ -7,6 +7,7 @@ AllCops:
|
|
7
7
|
Metrics/BlockLength:
|
8
8
|
Exclude:
|
9
9
|
- 'spec/**/*_spec.rb'
|
10
|
+
- 'spec/dummy/db/schema.rb'
|
10
11
|
- 'spec/support/shared_*/**/*.rb'
|
11
12
|
- 'azeroth.gemspec'
|
12
13
|
|
@@ -24,3 +25,13 @@ Style/HashTransformKeys:
|
|
24
25
|
|
25
26
|
Style/HashTransformValues:
|
26
27
|
Enabled: true
|
28
|
+
|
29
|
+
RSpec/ExampleLength:
|
30
|
+
Exclude:
|
31
|
+
- 'spec/integration/readme/**/*_spec.rb'
|
32
|
+
- 'spec/integration/yard/**/*_spec.rb'
|
33
|
+
|
34
|
+
RSpec/MultipleExpectations:
|
35
|
+
Exclude:
|
36
|
+
- 'spec/integration/readme/**/*_spec.rb'
|
37
|
+
- 'spec/integration/yard/**/*_spec.rb'
|
data/Dockerfile
CHANGED
data/README.md
CHANGED
@@ -11,4 +11,167 @@ Azeroth
|
|
11
11
|
|
12
12
|
Yard Documentation
|
13
13
|
-------------------
|
14
|
-
[https://www.rubydoc.info/gems/azeroth/0.
|
14
|
+
[https://www.rubydoc.info/gems/azeroth/0.7.1](https://www.rubydoc.info/gems/azeroth/0.7.2)
|
15
|
+
|
16
|
+
Azeroth has been designed making the coding of controllers easier
|
17
|
+
as routes in controllers are usually copy, paste and replace of same
|
18
|
+
code.
|
19
|
+
|
20
|
+
Azeroth was originally developed for controller actions
|
21
|
+
which will respond with json or template rendering based
|
22
|
+
on the requested format `.json` or `.html` where `html` rendering
|
23
|
+
does not perform database operations
|
24
|
+
|
25
|
+
Future versions will enable `html` rendering to also perform
|
26
|
+
database operations.
|
27
|
+
|
28
|
+
Installation
|
29
|
+
---------------
|
30
|
+
|
31
|
+
- Install it
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem install azeroth
|
35
|
+
```
|
36
|
+
|
37
|
+
- Or add Sinclair to your `Gemfile` and `bundle install`:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
gem 'azeroth'
|
41
|
+
```
|
42
|
+
|
43
|
+
```bash
|
44
|
+
bundle install azeroth
|
45
|
+
```
|
46
|
+
|
47
|
+
Usage
|
48
|
+
-----
|
49
|
+
|
50
|
+
## Azeroth::Resourceable
|
51
|
+
|
52
|
+
[Resourceable](https://www.rubydoc.info/gems/azeroth/Azeroth/Resourceable)
|
53
|
+
module adds class method [resource_for](https://www.rubydoc.info/gems/azeroth/Azeroth/Resourceable/ClassMethods#resource_for-instance_method)
|
54
|
+
which adds a resource and action methods for `create`, `show`, `index`,
|
55
|
+
`update`, `delete`, `edit`
|
56
|
+
|
57
|
+
It accepts options
|
58
|
+
- only: List of actions to be built
|
59
|
+
- except: List of actions to not to be built
|
60
|
+
- decorator: Decorator class or flag allowing/disallowing decorators
|
61
|
+
- before_save: Method/Proc to be ran before saving the resource on create or update
|
62
|
+
- build_with: Method/Block to be ran when building the reource on create
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# publishers_controller.rb
|
66
|
+
|
67
|
+
class PublishersController < ApplicationController
|
68
|
+
include Azeroth::Resourceable
|
69
|
+
skip_before_action :verify_authenticity_token
|
70
|
+
|
71
|
+
resource_for :publisher, only: %i[create index]
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# games_controller.rb
|
77
|
+
|
78
|
+
class GamesController < ApplicationController
|
79
|
+
include Azeroth::Resourceable
|
80
|
+
skip_before_action :verify_authenticity_token
|
81
|
+
|
82
|
+
resource_for :game, except: :delete
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def games
|
87
|
+
publisher.games
|
88
|
+
end
|
89
|
+
|
90
|
+
def publisher
|
91
|
+
@publisher ||= Publisher.find(publisher_id)
|
92
|
+
end
|
93
|
+
|
94
|
+
def publisher_id
|
95
|
+
params.require(:publisher_id)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
# pokemons_controller.rb
|
102
|
+
|
103
|
+
class PokemonsController < ApplicationController
|
104
|
+
include Azeroth::Resourceable
|
105
|
+
|
106
|
+
resource_for :pokemon,
|
107
|
+
only: %i[create update],
|
108
|
+
before_save: :set_favorite
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def set_favorite
|
113
|
+
pokemon.favorite = true
|
114
|
+
end
|
115
|
+
|
116
|
+
def pokemons
|
117
|
+
master.pokemons
|
118
|
+
end
|
119
|
+
|
120
|
+
def master
|
121
|
+
@master ||= PokemonMaster.find(master_id)
|
122
|
+
end
|
123
|
+
|
124
|
+
def master_id
|
125
|
+
params.require(:pokemon_master_id)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
## Azeroth::Decorator
|
131
|
+
|
132
|
+
[Decorators](https://www.rubydoc.info/gems/azeroth/Azeroth/Decorator) are
|
133
|
+
used to define how an object is exposed as json on controller responses
|
134
|
+
defining which and how fields will be exposed
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
# pokemon/decorator.rb
|
138
|
+
|
139
|
+
class Pokemon::Decorator < Azeroth::Decorator
|
140
|
+
expose :name
|
141
|
+
expose :previous_form_name, as: :evolution_of, if: :evolution?
|
142
|
+
|
143
|
+
def evolution?
|
144
|
+
previous_form
|
145
|
+
end
|
146
|
+
|
147
|
+
def previous_form_name
|
148
|
+
previous_form.name
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
# pokemon/favorite_decorator.rb
|
155
|
+
|
156
|
+
class Pokemon::FavoriteDecorator < Pokemon::Decorator
|
157
|
+
expose :nickname
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# pokemon_master/decorator.rb
|
163
|
+
|
164
|
+
class PokemonMaster < ActiveRecord::Base
|
165
|
+
has_one :favorite_pokemon, -> { where(favorite: true) },
|
166
|
+
class_name: 'Pokemon'
|
167
|
+
has_many :pokemons
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
Exposing is done through the class method
|
172
|
+
[expose](https://www.rubydoc.info/gems/azeroth/Azeroth/Decorator#expose-class_method)
|
173
|
+
which accepts several options:
|
174
|
+
|
175
|
+
- as: custom key to expose
|
176
|
+
- if: method/block to be called checking if an attribute should or should not be exposed
|
177
|
+
- decorator: flag to use or not a decorator or decorator class to be used
|
data/azeroth.gemspec
CHANGED
@@ -18,18 +18,19 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ['lib']
|
20
20
|
|
21
|
-
gem.add_runtime_dependency 'activesupport', '~> 5.2.
|
21
|
+
gem.add_runtime_dependency 'activesupport', '~> 5.2.4.3'
|
22
22
|
gem.add_runtime_dependency 'darthjee-active_ext', '>= 1.3.2'
|
23
|
-
gem.add_runtime_dependency '
|
23
|
+
gem.add_runtime_dependency 'jace', '>= 0.0.3'
|
24
|
+
gem.add_runtime_dependency 'sinclair', '>= 1.6.5'
|
24
25
|
|
25
|
-
gem.add_development_dependency 'actionpack', '5.2.4.
|
26
|
-
gem.add_development_dependency 'activerecord', '5.2.4.
|
26
|
+
gem.add_development_dependency 'actionpack', '5.2.4.3'
|
27
|
+
gem.add_development_dependency 'activerecord', '5.2.4.3'
|
27
28
|
gem.add_development_dependency 'bundler', '1.16.1'
|
28
29
|
gem.add_development_dependency 'factory_bot', '5.2.0'
|
29
30
|
gem.add_development_dependency 'nokogiri', '1.10.9'
|
30
31
|
gem.add_development_dependency 'pry', '0.12.2'
|
31
32
|
gem.add_development_dependency 'pry-nav', '0.3.0'
|
32
|
-
gem.add_development_dependency 'rails', '5.2.4.
|
33
|
+
gem.add_development_dependency 'rails', '5.2.4.3'
|
33
34
|
gem.add_development_dependency 'rails-controller-testing', '1.0.4'
|
34
35
|
gem.add_development_dependency 'rake', '13.0.1'
|
35
36
|
gem.add_development_dependency 'reek', '5.6.0'
|
data/lib/azeroth.rb
CHANGED
data/lib/azeroth/decorator.rb
CHANGED
@@ -84,6 +84,8 @@ module Azeroth
|
|
84
84
|
# to be called
|
85
85
|
# checking if an attribute should or should not
|
86
86
|
# be exposed
|
87
|
+
# @option options_hash decorator [FalseClass,TrueClass,Class]
|
88
|
+
# flag to use or not a decorator or decorator class to be used
|
87
89
|
#
|
88
90
|
# @return [Array<Symbol>]
|
89
91
|
#
|
@@ -104,6 +106,125 @@ module Azeroth
|
|
104
106
|
# end
|
105
107
|
# end
|
106
108
|
# end
|
109
|
+
#
|
110
|
+
# @example With relations
|
111
|
+
# # pokemon/decorator.rb
|
112
|
+
#
|
113
|
+
# class Pokemon::Decorator < Azeroth::Decorator
|
114
|
+
# expose :name
|
115
|
+
# expose :previous_form_name, as: :evolution_of, if: :evolution?
|
116
|
+
#
|
117
|
+
# def evolution?
|
118
|
+
# previous_form
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# def previous_form_name
|
122
|
+
# previous_form.name
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# # pokemon/favorite_decorator.rb
|
127
|
+
#
|
128
|
+
# class Pokemon::FavoriteDecorator < Pokemon::Decorator
|
129
|
+
# expose :nickname
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# # pokemon_master/decorator.rb
|
133
|
+
#
|
134
|
+
# class PokemonMaster < ActiveRecord::Base
|
135
|
+
# has_one :favorite_pokemon, -> { where(favorite: true) },
|
136
|
+
# class_name: 'Pokemon'
|
137
|
+
# has_many :pokemons
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# # pokemon.rb
|
141
|
+
#
|
142
|
+
# class Pokemon < ActiveRecord::Base
|
143
|
+
# belongs_to :pokemon_master
|
144
|
+
# has_one :previous_form,
|
145
|
+
# class_name: 'Pokemon',
|
146
|
+
# foreign_key: :previous_form_id
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# # pokemon_master.rb
|
150
|
+
#
|
151
|
+
# class PokemonMaster::Decorator < Azeroth::Decorator
|
152
|
+
# expose :name
|
153
|
+
# expose :age
|
154
|
+
# expose :favorite_pokemon, decorator: Pokemon::FavoriteDecorator
|
155
|
+
# expose :pokemons
|
156
|
+
#
|
157
|
+
# def name
|
158
|
+
# [
|
159
|
+
# first_name,
|
160
|
+
# last_name
|
161
|
+
# ].compact.join(' ')
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# # schema.rb
|
166
|
+
#
|
167
|
+
# ActiveRecord::Schema.define do
|
168
|
+
# self.verbose = false
|
169
|
+
#
|
170
|
+
# create_table :pokemon_masters, force: true do |t|
|
171
|
+
# t.string :first_name, null: false
|
172
|
+
# t.string :last_name
|
173
|
+
# t.integer :age, null: false
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# create_table :pokemons, force: true do |t|
|
177
|
+
# t.string :name, null: false
|
178
|
+
# t.string :nickname
|
179
|
+
# t.integer :pokemon_master_id
|
180
|
+
# t.boolean :favorite
|
181
|
+
# t.integer :previous_form_id
|
182
|
+
# t.index %i[pokemon_master_id favorite], unique: true
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# add_foreign_key 'pokemons', 'pokemon_masters'
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# # test.rb
|
189
|
+
#
|
190
|
+
# master = PokemonMaster.create(
|
191
|
+
# first_name: 'Ash',
|
192
|
+
# last_name: 'Ketchum',
|
193
|
+
# age: 10
|
194
|
+
# )
|
195
|
+
#
|
196
|
+
# master.create_favorite_pokemon(
|
197
|
+
# name: 'pikachu',
|
198
|
+
# nickname: 'Pikachu'
|
199
|
+
# )
|
200
|
+
#
|
201
|
+
# metapod = Pokemon.create(name: :metapod)
|
202
|
+
#
|
203
|
+
# master.pokemons.create(
|
204
|
+
# name: 'butterfree', previous_form: metapod
|
205
|
+
# )
|
206
|
+
# master.pokemons.create(name: 'squirtle')
|
207
|
+
#
|
208
|
+
# decorator = PokemonMaster::Decorator.new(master)
|
209
|
+
#
|
210
|
+
# decorator.as_json
|
211
|
+
# # returns
|
212
|
+
# # {
|
213
|
+
# # 'age' => 10,
|
214
|
+
# # 'name' => 'Ash Ketchum',
|
215
|
+
# # 'favorite_pokemon' => {
|
216
|
+
# # 'name' => 'pikachu',
|
217
|
+
# # 'nickname' => 'Pikachu'
|
218
|
+
# # },
|
219
|
+
# # 'pokemons' => [{
|
220
|
+
# # 'name' => 'butterfree',
|
221
|
+
# # 'evolution_of' => 'metapod'
|
222
|
+
# # }, {
|
223
|
+
# # 'name' => 'squirtle'
|
224
|
+
# # }, {
|
225
|
+
# # 'name' => 'pikachu'
|
226
|
+
# # }]
|
227
|
+
# # }
|
107
228
|
def expose(attribute, **options_hash)
|
108
229
|
options = Decorator::Options.new(options_hash)
|
109
230
|
|
@@ -136,6 +257,8 @@ module Azeroth
|
|
136
257
|
#
|
137
258
|
# @return [Hash]
|
138
259
|
def as_json(*args)
|
260
|
+
return nil if object.nil?
|
261
|
+
|
139
262
|
return array_as_json(*args) if enum?
|
140
263
|
|
141
264
|
HashBuilder.new(self).as_json
|
@@ -97,9 +97,9 @@ module Azeroth
|
|
97
97
|
#
|
98
98
|
# @return [Class<Decorator>, NilClass]
|
99
99
|
def decorator_from_options
|
100
|
-
return options.decorator if options.
|
100
|
+
return options.decorator if options.decorator_defined?
|
101
101
|
|
102
|
-
Azeroth::DummyDecorator unless options.
|
102
|
+
Azeroth::DummyDecorator unless options.decorator
|
103
103
|
end
|
104
104
|
|
105
105
|
# @private
|