praxis 2.0.pre.32 → 2.0.pre.33
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/.travis.yml +4 -1
- data/Appraisals +11 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +6 -6
- data/gemfiles/active_6.gemfile +16 -0
- data/gemfiles/active_6.gemfile.lock +199 -0
- data/gemfiles/active_7.gemfile +16 -0
- data/gemfiles/active_7.gemfile.lock +197 -0
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
- data/lib/praxis/blueprint.rb +8 -9
- data/lib/praxis/blueprint_attribute_group.rb +0 -2
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +4 -4
- data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +6 -12
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +2 -0
- data/lib/praxis/extensions/pagination/pagination_params.rb +2 -2
- data/lib/praxis/mapper/active_model_compat.rb +4 -6
- data/lib/praxis/media_type_identifier.rb +4 -4
- data/lib/praxis/types/multipart_array.rb +3 -3
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +2 -4
- data/spec/praxis/blueprint_spec.rb +292 -17
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +28 -0
- data/spec/support/spec_blueprints.rb +6 -4
- metadata +23 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9bdbabd51b8b6bb4a776ab4c728d36b3cf86f3b7a3423250e6658fa01653ba6a
|
|
4
|
+
data.tar.gz: e9edc1eacc8ebf67d8f8b5fdda19cb010b587f3e2d0319cbcdeec62908752d8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 174e74b7e4e55378edde0f623b4f2c49aa15409bfc64ae9f36aa8a0167794ed1c3b747331da5bdc66e672bcb58228cbaad89971689449d082d5080c009b7ad6c
|
|
7
|
+
data.tar.gz: c7574f73697e2067e6f338d1c19bdc6447ca24620ed49a1ff94882392c8df987cbc598624323ce3228330c27ce0dda7b4f0228b68a4ad18dbf6c37c995869e84
|
data/.travis.yml
CHANGED
data/Appraisals
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
appraise "active-6" do
|
|
2
|
+
# Just for the query selector/filtering/ordering extensions etc...
|
|
3
|
+
gem 'activerecord', '> 4', '< 7'
|
|
4
|
+
gem 'sequel', '~> 5'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
appraise "active-7" do
|
|
8
|
+
# Just for the query selector/filtering/ordering extensions etc...
|
|
9
|
+
gem 'activerecord', '>=7'
|
|
10
|
+
gem 'sequel', '~> 5'
|
|
11
|
+
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Praxis Changelog
|
|
2
2
|
|
|
3
3
|
## next
|
|
4
|
+
- Better support for ordefing in newer versions of MySQL:
|
|
5
|
+
* Some versions will complain on an invalid query if you use an ORDER BY component that does not have the corresponding SELECT field
|
|
6
|
+
- Use the newest Attributor gem, which revamps and hardnens the struct/collection definion DSL, and provides much better error messages and safety. It also
|
|
7
|
+
bring the ability to define collections with `<T>[]` which is equivalent to the current `Attributor::Collection.of(<T>). For example, you can now do things
|
|
8
|
+
like `String[]`, `MyMediaType[]`, etc..
|
|
9
|
+
- Tightened a few type comparisons throughout the framework, and built full specs for struct/collection definitions in Blueprints.
|
|
10
|
+
- Built config for the Appraisals gem, so we can continuously test some of our extensions against different versions of ActiveRecord as it evolves (6x and7x for now)
|
|
4
11
|
|
|
5
12
|
## 2.0.pre.32
|
|
6
13
|
- Spruced up the scaffolding generation, to be more configurable using a `.praxis_scaffold` file at the root, where one can specify things like
|
data/Gemfile
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
source
|
|
3
|
+
source "https://rubygems.org"
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
|
-
gem
|
|
6
|
+
gem "rubocop"
|
|
7
7
|
|
|
8
8
|
group :test do
|
|
9
|
-
gem
|
|
9
|
+
gem "builder"
|
|
10
10
|
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
11
|
+
gem "link_header"
|
|
12
|
+
gem "oj"
|
|
13
|
+
gem "parslet"
|
|
14
14
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "rubocop"
|
|
6
|
+
gem "activerecord", "> 4", "< 7"
|
|
7
|
+
gem "sequel", "~> 5"
|
|
8
|
+
|
|
9
|
+
group :test do
|
|
10
|
+
gem "builder"
|
|
11
|
+
gem "link_header"
|
|
12
|
+
gem "oj"
|
|
13
|
+
gem "parslet"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
praxis (2.0.pre.32)
|
|
5
|
+
activesupport (>= 3)
|
|
6
|
+
attributor (>= 6.5)
|
|
7
|
+
mime (~> 0)
|
|
8
|
+
mustermann (>= 1.1)
|
|
9
|
+
rack (>= 1)
|
|
10
|
+
terminal-table (~> 1.4)
|
|
11
|
+
thor
|
|
12
|
+
|
|
13
|
+
GEM
|
|
14
|
+
remote: https://rubygems.org/
|
|
15
|
+
specs:
|
|
16
|
+
activemodel (6.1.7.3)
|
|
17
|
+
activesupport (= 6.1.7.3)
|
|
18
|
+
activerecord (6.1.7.3)
|
|
19
|
+
activemodel (= 6.1.7.3)
|
|
20
|
+
activesupport (= 6.1.7.3)
|
|
21
|
+
activesupport (6.1.7.3)
|
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
23
|
+
i18n (>= 1.6, < 2)
|
|
24
|
+
minitest (>= 5.1)
|
|
25
|
+
tzinfo (~> 2.0)
|
|
26
|
+
zeitwerk (~> 2.3)
|
|
27
|
+
appraisal (2.4.1)
|
|
28
|
+
bundler
|
|
29
|
+
rake
|
|
30
|
+
thor (>= 0.14.0)
|
|
31
|
+
ast (2.4.2)
|
|
32
|
+
attributor (6.5)
|
|
33
|
+
activesupport (>= 3)
|
|
34
|
+
hashie (~> 3)
|
|
35
|
+
randexp (~> 0)
|
|
36
|
+
binding_of_caller (1.0.0)
|
|
37
|
+
debug_inspector (>= 0.0.1)
|
|
38
|
+
builder (3.2.4)
|
|
39
|
+
byebug (11.1.3)
|
|
40
|
+
coderay (1.1.3)
|
|
41
|
+
concurrent-ruby (1.2.2)
|
|
42
|
+
coveralls (0.8.23)
|
|
43
|
+
json (>= 1.8, < 3)
|
|
44
|
+
simplecov (~> 0.16.1)
|
|
45
|
+
term-ansicolor (~> 1.3)
|
|
46
|
+
thor (>= 0.19.4, < 2.0)
|
|
47
|
+
tins (~> 1.6)
|
|
48
|
+
debug_inspector (1.1.0)
|
|
49
|
+
diff-lcs (1.5.0)
|
|
50
|
+
docile (1.4.0)
|
|
51
|
+
ffi (1.15.5)
|
|
52
|
+
formatador (1.1.0)
|
|
53
|
+
fuubar (2.5.1)
|
|
54
|
+
rspec-core (~> 3.0)
|
|
55
|
+
ruby-progressbar (~> 1.4)
|
|
56
|
+
guard (2.18.0)
|
|
57
|
+
formatador (>= 0.2.4)
|
|
58
|
+
listen (>= 2.7, < 4.0)
|
|
59
|
+
lumberjack (>= 1.0.12, < 2.0)
|
|
60
|
+
nenv (~> 0.1)
|
|
61
|
+
notiffany (~> 0.0)
|
|
62
|
+
pry (>= 0.13.0)
|
|
63
|
+
shellany (~> 0.0)
|
|
64
|
+
thor (>= 0.18.1)
|
|
65
|
+
guard-bundler (2.2.1)
|
|
66
|
+
bundler (>= 1.3.0, < 3)
|
|
67
|
+
guard (~> 2.2)
|
|
68
|
+
guard-compat (~> 1.1)
|
|
69
|
+
guard-compat (1.2.1)
|
|
70
|
+
guard-rspec (4.7.3)
|
|
71
|
+
guard (~> 2.1)
|
|
72
|
+
guard-compat (~> 1.1)
|
|
73
|
+
rspec (>= 2.99.0, < 4.0)
|
|
74
|
+
hashie (3.6.0)
|
|
75
|
+
i18n (1.13.0)
|
|
76
|
+
concurrent-ruby (~> 1.0)
|
|
77
|
+
json (2.6.3)
|
|
78
|
+
link_header (0.0.8)
|
|
79
|
+
listen (3.8.0)
|
|
80
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
81
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
|
82
|
+
lumberjack (1.2.8)
|
|
83
|
+
method_source (1.0.0)
|
|
84
|
+
mime (0.4.4)
|
|
85
|
+
minitest (5.18.0)
|
|
86
|
+
mustermann (3.0.0)
|
|
87
|
+
ruby2_keywords (~> 0.0.1)
|
|
88
|
+
nenv (0.3.0)
|
|
89
|
+
notiffany (0.1.3)
|
|
90
|
+
nenv (~> 0.1)
|
|
91
|
+
shellany (~> 0.0)
|
|
92
|
+
oj (3.14.2)
|
|
93
|
+
parallel (1.23.0)
|
|
94
|
+
parser (3.2.2.1)
|
|
95
|
+
ast (~> 2.4.1)
|
|
96
|
+
parslet (2.0.0)
|
|
97
|
+
pry (0.14.2)
|
|
98
|
+
coderay (~> 1.1)
|
|
99
|
+
method_source (~> 1.0)
|
|
100
|
+
pry-byebug (3.10.1)
|
|
101
|
+
byebug (~> 11.0)
|
|
102
|
+
pry (>= 0.13, < 0.15)
|
|
103
|
+
pry-stack_explorer (0.6.1)
|
|
104
|
+
binding_of_caller (~> 1.0)
|
|
105
|
+
pry (~> 0.13)
|
|
106
|
+
rack (2.2.7)
|
|
107
|
+
rack-test (0.8.3)
|
|
108
|
+
rack (>= 1.0, < 3)
|
|
109
|
+
rainbow (3.1.1)
|
|
110
|
+
rake (13.0.6)
|
|
111
|
+
randexp (0.1.7)
|
|
112
|
+
rb-fsevent (0.11.2)
|
|
113
|
+
rb-inotify (0.10.1)
|
|
114
|
+
ffi (~> 1.0)
|
|
115
|
+
regexp_parser (2.8.0)
|
|
116
|
+
rexml (3.2.5)
|
|
117
|
+
rspec (3.12.0)
|
|
118
|
+
rspec-core (~> 3.12.0)
|
|
119
|
+
rspec-expectations (~> 3.12.0)
|
|
120
|
+
rspec-mocks (~> 3.12.0)
|
|
121
|
+
rspec-collection_matchers (1.2.0)
|
|
122
|
+
rspec-expectations (>= 2.99.0.beta1)
|
|
123
|
+
rspec-core (3.12.1)
|
|
124
|
+
rspec-support (~> 3.12.0)
|
|
125
|
+
rspec-expectations (3.12.2)
|
|
126
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
127
|
+
rspec-support (~> 3.12.0)
|
|
128
|
+
rspec-its (1.3.0)
|
|
129
|
+
rspec-core (>= 3.0.0)
|
|
130
|
+
rspec-expectations (>= 3.0.0)
|
|
131
|
+
rspec-mocks (3.12.3)
|
|
132
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
133
|
+
rspec-support (~> 3.12.0)
|
|
134
|
+
rspec-support (3.12.0)
|
|
135
|
+
rubocop (1.48.1)
|
|
136
|
+
json (~> 2.3)
|
|
137
|
+
parallel (~> 1.10)
|
|
138
|
+
parser (>= 3.2.0.0)
|
|
139
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
140
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
141
|
+
rexml (>= 3.2.5, < 4.0)
|
|
142
|
+
rubocop-ast (>= 1.26.0, < 2.0)
|
|
143
|
+
ruby-progressbar (~> 1.7)
|
|
144
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
145
|
+
rubocop-ast (1.28.0)
|
|
146
|
+
parser (>= 3.2.1.0)
|
|
147
|
+
ruby-progressbar (1.13.0)
|
|
148
|
+
ruby2_keywords (0.0.5)
|
|
149
|
+
sequel (5.55.0)
|
|
150
|
+
shellany (0.0.1)
|
|
151
|
+
simplecov (0.16.1)
|
|
152
|
+
docile (~> 1.1)
|
|
153
|
+
json (>= 1.8, < 3)
|
|
154
|
+
simplecov-html (~> 0.10.0)
|
|
155
|
+
simplecov-html (0.10.2)
|
|
156
|
+
sqlite3 (1.6.1-x86_64-darwin)
|
|
157
|
+
sync (0.5.0)
|
|
158
|
+
term-ansicolor (1.7.1)
|
|
159
|
+
tins (~> 1.0)
|
|
160
|
+
terminal-table (1.6.0)
|
|
161
|
+
thor (1.2.2)
|
|
162
|
+
tins (1.31.0)
|
|
163
|
+
sync
|
|
164
|
+
tzinfo (2.0.6)
|
|
165
|
+
concurrent-ruby (~> 1.0)
|
|
166
|
+
unicode-display_width (2.4.2)
|
|
167
|
+
zeitwerk (2.6.8)
|
|
168
|
+
|
|
169
|
+
PLATFORMS
|
|
170
|
+
x86_64-darwin-20
|
|
171
|
+
|
|
172
|
+
DEPENDENCIES
|
|
173
|
+
activerecord (> 4, < 7)
|
|
174
|
+
appraisal
|
|
175
|
+
builder
|
|
176
|
+
bundler
|
|
177
|
+
coveralls
|
|
178
|
+
fuubar (~> 2)
|
|
179
|
+
guard (~> 2)
|
|
180
|
+
guard-bundler (~> 2)
|
|
181
|
+
guard-rspec (~> 4)
|
|
182
|
+
link_header
|
|
183
|
+
oj
|
|
184
|
+
parslet
|
|
185
|
+
praxis!
|
|
186
|
+
pry
|
|
187
|
+
pry-byebug
|
|
188
|
+
pry-stack_explorer
|
|
189
|
+
rack-test (~> 0)
|
|
190
|
+
rake (>= 12.3.3)
|
|
191
|
+
rspec (~> 3)
|
|
192
|
+
rspec-collection_matchers (~> 1)
|
|
193
|
+
rspec-its (~> 1)
|
|
194
|
+
rubocop
|
|
195
|
+
sequel (~> 5)
|
|
196
|
+
sqlite3 (~> 1)
|
|
197
|
+
|
|
198
|
+
BUNDLED WITH
|
|
199
|
+
2.4.12
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "rubocop"
|
|
6
|
+
gem "activerecord", ">=7"
|
|
7
|
+
gem "sequel", "~> 5"
|
|
8
|
+
|
|
9
|
+
group :test do
|
|
10
|
+
gem "builder"
|
|
11
|
+
gem "link_header"
|
|
12
|
+
gem "oj"
|
|
13
|
+
gem "parslet"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
praxis (2.0.pre.32)
|
|
5
|
+
activesupport (>= 3)
|
|
6
|
+
attributor (>= 6.5)
|
|
7
|
+
mime (~> 0)
|
|
8
|
+
mustermann (>= 1.1)
|
|
9
|
+
rack (>= 1)
|
|
10
|
+
terminal-table (~> 1.4)
|
|
11
|
+
thor
|
|
12
|
+
|
|
13
|
+
GEM
|
|
14
|
+
remote: https://rubygems.org/
|
|
15
|
+
specs:
|
|
16
|
+
activemodel (7.0.4.2)
|
|
17
|
+
activesupport (= 7.0.4.2)
|
|
18
|
+
activerecord (7.0.4.2)
|
|
19
|
+
activemodel (= 7.0.4.2)
|
|
20
|
+
activesupport (= 7.0.4.2)
|
|
21
|
+
activesupport (7.0.4.2)
|
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
23
|
+
i18n (>= 1.6, < 2)
|
|
24
|
+
minitest (>= 5.1)
|
|
25
|
+
tzinfo (~> 2.0)
|
|
26
|
+
appraisal (2.4.1)
|
|
27
|
+
bundler
|
|
28
|
+
rake
|
|
29
|
+
thor (>= 0.14.0)
|
|
30
|
+
ast (2.4.2)
|
|
31
|
+
attributor (6.5)
|
|
32
|
+
activesupport (>= 3)
|
|
33
|
+
hashie (~> 3)
|
|
34
|
+
randexp (~> 0)
|
|
35
|
+
binding_of_caller (1.0.0)
|
|
36
|
+
debug_inspector (>= 0.0.1)
|
|
37
|
+
builder (3.2.4)
|
|
38
|
+
byebug (11.1.3)
|
|
39
|
+
coderay (1.1.3)
|
|
40
|
+
concurrent-ruby (1.2.2)
|
|
41
|
+
coveralls (0.8.23)
|
|
42
|
+
json (>= 1.8, < 3)
|
|
43
|
+
simplecov (~> 0.16.1)
|
|
44
|
+
term-ansicolor (~> 1.3)
|
|
45
|
+
thor (>= 0.19.4, < 2.0)
|
|
46
|
+
tins (~> 1.6)
|
|
47
|
+
debug_inspector (1.1.0)
|
|
48
|
+
diff-lcs (1.5.0)
|
|
49
|
+
docile (1.4.0)
|
|
50
|
+
ffi (1.15.5)
|
|
51
|
+
formatador (1.1.0)
|
|
52
|
+
fuubar (2.5.1)
|
|
53
|
+
rspec-core (~> 3.0)
|
|
54
|
+
ruby-progressbar (~> 1.4)
|
|
55
|
+
guard (2.18.0)
|
|
56
|
+
formatador (>= 0.2.4)
|
|
57
|
+
listen (>= 2.7, < 4.0)
|
|
58
|
+
lumberjack (>= 1.0.12, < 2.0)
|
|
59
|
+
nenv (~> 0.1)
|
|
60
|
+
notiffany (~> 0.0)
|
|
61
|
+
pry (>= 0.13.0)
|
|
62
|
+
shellany (~> 0.0)
|
|
63
|
+
thor (>= 0.18.1)
|
|
64
|
+
guard-bundler (2.2.1)
|
|
65
|
+
bundler (>= 1.3.0, < 3)
|
|
66
|
+
guard (~> 2.2)
|
|
67
|
+
guard-compat (~> 1.1)
|
|
68
|
+
guard-compat (1.2.1)
|
|
69
|
+
guard-rspec (4.7.3)
|
|
70
|
+
guard (~> 2.1)
|
|
71
|
+
guard-compat (~> 1.1)
|
|
72
|
+
rspec (>= 2.99.0, < 4.0)
|
|
73
|
+
hashie (3.6.0)
|
|
74
|
+
i18n (1.13.0)
|
|
75
|
+
concurrent-ruby (~> 1.0)
|
|
76
|
+
json (2.6.3)
|
|
77
|
+
link_header (0.0.8)
|
|
78
|
+
listen (3.8.0)
|
|
79
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
80
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
|
81
|
+
lumberjack (1.2.8)
|
|
82
|
+
method_source (1.0.0)
|
|
83
|
+
mime (0.4.4)
|
|
84
|
+
minitest (5.18.0)
|
|
85
|
+
mustermann (3.0.0)
|
|
86
|
+
ruby2_keywords (~> 0.0.1)
|
|
87
|
+
nenv (0.3.0)
|
|
88
|
+
notiffany (0.1.3)
|
|
89
|
+
nenv (~> 0.1)
|
|
90
|
+
shellany (~> 0.0)
|
|
91
|
+
oj (3.14.2)
|
|
92
|
+
parallel (1.23.0)
|
|
93
|
+
parser (3.2.2.1)
|
|
94
|
+
ast (~> 2.4.1)
|
|
95
|
+
parslet (2.0.0)
|
|
96
|
+
pry (0.14.2)
|
|
97
|
+
coderay (~> 1.1)
|
|
98
|
+
method_source (~> 1.0)
|
|
99
|
+
pry-byebug (3.10.1)
|
|
100
|
+
byebug (~> 11.0)
|
|
101
|
+
pry (>= 0.13, < 0.15)
|
|
102
|
+
pry-stack_explorer (0.6.1)
|
|
103
|
+
binding_of_caller (~> 1.0)
|
|
104
|
+
pry (~> 0.13)
|
|
105
|
+
rack (2.2.7)
|
|
106
|
+
rack-test (0.8.3)
|
|
107
|
+
rack (>= 1.0, < 3)
|
|
108
|
+
rainbow (3.1.1)
|
|
109
|
+
rake (13.0.6)
|
|
110
|
+
randexp (0.1.7)
|
|
111
|
+
rb-fsevent (0.11.2)
|
|
112
|
+
rb-inotify (0.10.1)
|
|
113
|
+
ffi (~> 1.0)
|
|
114
|
+
regexp_parser (2.8.0)
|
|
115
|
+
rexml (3.2.5)
|
|
116
|
+
rspec (3.12.0)
|
|
117
|
+
rspec-core (~> 3.12.0)
|
|
118
|
+
rspec-expectations (~> 3.12.0)
|
|
119
|
+
rspec-mocks (~> 3.12.0)
|
|
120
|
+
rspec-collection_matchers (1.2.0)
|
|
121
|
+
rspec-expectations (>= 2.99.0.beta1)
|
|
122
|
+
rspec-core (3.12.1)
|
|
123
|
+
rspec-support (~> 3.12.0)
|
|
124
|
+
rspec-expectations (3.12.2)
|
|
125
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
126
|
+
rspec-support (~> 3.12.0)
|
|
127
|
+
rspec-its (1.3.0)
|
|
128
|
+
rspec-core (>= 3.0.0)
|
|
129
|
+
rspec-expectations (>= 3.0.0)
|
|
130
|
+
rspec-mocks (3.12.3)
|
|
131
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
132
|
+
rspec-support (~> 3.12.0)
|
|
133
|
+
rspec-support (3.12.0)
|
|
134
|
+
rubocop (1.48.1)
|
|
135
|
+
json (~> 2.3)
|
|
136
|
+
parallel (~> 1.10)
|
|
137
|
+
parser (>= 3.2.0.0)
|
|
138
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
139
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
140
|
+
rexml (>= 3.2.5, < 4.0)
|
|
141
|
+
rubocop-ast (>= 1.26.0, < 2.0)
|
|
142
|
+
ruby-progressbar (~> 1.7)
|
|
143
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
144
|
+
rubocop-ast (1.28.0)
|
|
145
|
+
parser (>= 3.2.1.0)
|
|
146
|
+
ruby-progressbar (1.13.0)
|
|
147
|
+
ruby2_keywords (0.0.5)
|
|
148
|
+
sequel (5.55.0)
|
|
149
|
+
shellany (0.0.1)
|
|
150
|
+
simplecov (0.16.1)
|
|
151
|
+
docile (~> 1.1)
|
|
152
|
+
json (>= 1.8, < 3)
|
|
153
|
+
simplecov-html (~> 0.10.0)
|
|
154
|
+
simplecov-html (0.10.2)
|
|
155
|
+
sqlite3 (1.6.1-x86_64-darwin)
|
|
156
|
+
sync (0.5.0)
|
|
157
|
+
term-ansicolor (1.7.1)
|
|
158
|
+
tins (~> 1.0)
|
|
159
|
+
terminal-table (1.6.0)
|
|
160
|
+
thor (1.2.2)
|
|
161
|
+
tins (1.31.0)
|
|
162
|
+
sync
|
|
163
|
+
tzinfo (2.0.6)
|
|
164
|
+
concurrent-ruby (~> 1.0)
|
|
165
|
+
unicode-display_width (2.4.2)
|
|
166
|
+
|
|
167
|
+
PLATFORMS
|
|
168
|
+
x86_64-darwin-20
|
|
169
|
+
|
|
170
|
+
DEPENDENCIES
|
|
171
|
+
activerecord (>= 7)
|
|
172
|
+
appraisal
|
|
173
|
+
builder
|
|
174
|
+
bundler
|
|
175
|
+
coveralls
|
|
176
|
+
fuubar (~> 2)
|
|
177
|
+
guard (~> 2)
|
|
178
|
+
guard-bundler (~> 2)
|
|
179
|
+
guard-rspec (~> 4)
|
|
180
|
+
link_header
|
|
181
|
+
oj
|
|
182
|
+
parslet
|
|
183
|
+
praxis!
|
|
184
|
+
pry
|
|
185
|
+
pry-byebug
|
|
186
|
+
pry-stack_explorer
|
|
187
|
+
rack-test (~> 0)
|
|
188
|
+
rake (>= 12.3.3)
|
|
189
|
+
rspec (~> 3)
|
|
190
|
+
rspec-collection_matchers (~> 1)
|
|
191
|
+
rspec-its (~> 1)
|
|
192
|
+
rubocop
|
|
193
|
+
sequel (~> 5)
|
|
194
|
+
sqlite3 (~> 1)
|
|
195
|
+
|
|
196
|
+
BUNDLED WITH
|
|
197
|
+
2.4.12
|
|
@@ -18,7 +18,7 @@ module Praxis
|
|
|
18
18
|
case val
|
|
19
19
|
when Regexp
|
|
20
20
|
options[:regexp] = val
|
|
21
|
-
when String
|
|
21
|
+
when ::String
|
|
22
22
|
options[:values] = [val]
|
|
23
23
|
when nil
|
|
24
24
|
# Defining the existence without any other options can only mean that it is required (otherwise it is a useless definition)
|
data/lib/praxis/blueprint.rb
CHANGED
|
@@ -10,7 +10,8 @@ module Praxis
|
|
|
10
10
|
# aren't invoked by just merely loading, and only really invoked when we've asked to render them
|
|
11
11
|
# It takes the name of the group, and passes the attributes block that needs to be a subset of the MediaType where the group resides
|
|
12
12
|
def group(name, **options, &block)
|
|
13
|
-
|
|
13
|
+
# Pass the reference to the target type by default. But allow overriding it if needed
|
|
14
|
+
attribute(name, Praxis::BlueprintAttributeGroup.for(target), **{reference: target}.merge(options), &block)
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -62,7 +63,6 @@ module Praxis
|
|
|
62
63
|
|
|
63
64
|
class << self
|
|
64
65
|
attr_reader :attribute, :options
|
|
65
|
-
attr_accessor :reference
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def self.inherited(klass)
|
|
@@ -97,11 +97,7 @@ module Praxis
|
|
|
97
97
|
|
|
98
98
|
def self.attributes(opts = {}, &block)
|
|
99
99
|
if block_given?
|
|
100
|
-
raise 'Redefining Blueprint attributes is not currently supported' if const_defined?(:
|
|
101
|
-
|
|
102
|
-
raise "Reference mismatch in #{inspect}. Given :reference option #{opts[:reference].inspect}, while using #{reference.inspect}" if opts.key?(:reference) && opts[:reference] != reference
|
|
103
|
-
|
|
104
|
-
opts[:reference] = (reference || self)
|
|
100
|
+
raise 'Redefining Blueprint attributes is not currently supported' if const_defined?(:InnerStruct, false)
|
|
105
101
|
|
|
106
102
|
@options.merge!(opts.merge(dsl_compiler: DSLCompiler))
|
|
107
103
|
@block = block
|
|
@@ -133,7 +129,7 @@ module Praxis
|
|
|
133
129
|
new(value)
|
|
134
130
|
end
|
|
135
131
|
else
|
|
136
|
-
if value.is_a?(domain_model) || value.is_a?(self::
|
|
132
|
+
if value.is_a?(domain_model) || value.is_a?(self::InnerStruct)
|
|
137
133
|
# Wrap the value directly
|
|
138
134
|
new(value)
|
|
139
135
|
else
|
|
@@ -253,7 +249,7 @@ module Praxis
|
|
|
253
249
|
@attribute = Attributor::Attribute.new(Attributor::Struct, @options, &@block)
|
|
254
250
|
@block = nil
|
|
255
251
|
@attribute.type.anonymous_type true
|
|
256
|
-
const_set(:
|
|
252
|
+
const_set(:InnerStruct, @attribute.type)
|
|
257
253
|
end
|
|
258
254
|
|
|
259
255
|
def self.define_readers!
|
|
@@ -288,6 +284,8 @@ module Praxis
|
|
|
288
284
|
attributes.each do |name, attr|
|
|
289
285
|
the_type = attr.type < Attributor::Collection ? attr.type.member_type : attr.type
|
|
290
286
|
next if the_type < Blueprint
|
|
287
|
+
# TODO: Allow groups in the default fieldset?? or perhaps better to make people explicitly define them?
|
|
288
|
+
# next if (the_type < Blueprint && !(the_type < BlueprintAttributeGroup))
|
|
291
289
|
|
|
292
290
|
# NOTE: we won't try to expand fields here, as we want to be lazy (and we're expanding)
|
|
293
291
|
# every time a request comes in anyway. This could be an optimization we do at some point
|
|
@@ -353,6 +351,7 @@ module Praxis
|
|
|
353
351
|
|
|
354
352
|
leftover = self.class.attributes.keys - keys_provided
|
|
355
353
|
leftover.each do |key|
|
|
354
|
+
sub_context = self.class.generate_subcontext(context, key)
|
|
356
355
|
attribute = self.class.attributes[key]
|
|
357
356
|
|
|
358
357
|
errors.concat ["Attribute #{Attributor.humanize_context(sub_context)} is required."] if attribute.options[:required]
|
|
@@ -10,10 +10,8 @@ module Praxis
|
|
|
10
10
|
def self.construct(attribute_definition, options = {})
|
|
11
11
|
return self if attribute_definition.nil?
|
|
12
12
|
|
|
13
|
-
reference_type = @media_type
|
|
14
13
|
# Construct a group-derived class with the given mediatype as the reference
|
|
15
14
|
::Class.new(self) do
|
|
16
|
-
@reference = reference_type
|
|
17
15
|
attributes(**options, &attribute_definition)
|
|
18
16
|
end
|
|
19
17
|
end
|
|
@@ -34,7 +34,7 @@ module Praxis
|
|
|
34
34
|
@model = model
|
|
35
35
|
@filters_map = filters_map
|
|
36
36
|
@logger = debug ? Logger.new($stdout) : nil
|
|
37
|
-
@
|
|
37
|
+
@active_record_version = ActiveRecord.gem_version
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def debug_query(msg, query)
|
|
@@ -86,7 +86,8 @@ module Praxis
|
|
|
86
86
|
)
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
|
|
90
|
+
if @active_record_version < Gem::Version.new('6')
|
|
90
91
|
# ActiveRecord < 6 does not support '.and' so no nested things can be done
|
|
91
92
|
# But we can still support the case of 1+ flat conditions of the same AND/OR type
|
|
92
93
|
if root_parent_group.is_a?(FilteringParams::Condition)
|
|
@@ -347,8 +348,7 @@ module Praxis
|
|
|
347
348
|
end
|
|
348
349
|
|
|
349
350
|
# The value that we need to stick in the references method is different in the latest Rails
|
|
350
|
-
|
|
351
|
-
if maj == 5 || (maj == 6 && min.zero?)
|
|
351
|
+
if ActiveRecord.gem_version < Gem::Version.new('6')
|
|
352
352
|
# In AR 6 (and 6.0) the references are simple strings
|
|
353
353
|
def self.build_reference_value(column_prefix, **_args)
|
|
354
354
|
column_prefix
|
|
@@ -2,17 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_record'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
case maj
|
|
8
|
-
when 5
|
|
5
|
+
if ActiveRecord.gem_version < Gem::Version.new('6')
|
|
9
6
|
require_relative 'active_record_patches/5x'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
require_relative 'active_record_patches/6_0'
|
|
13
|
-
else
|
|
14
|
-
require_relative 'active_record_patches/6_1_plus'
|
|
15
|
-
end
|
|
7
|
+
elsif ActiveRecord.gem_version < Gem::Version.new('6.1')
|
|
8
|
+
require_relative 'active_record_patches/6_0'
|
|
16
9
|
else
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
# As of 7.0.4 our 6.1-plus patches still work
|
|
11
|
+
require_relative 'active_record_patches/6_1_plus'
|
|
12
|
+
end
|
|
@@ -45,6 +45,8 @@ module Praxis
|
|
|
45
45
|
quoted_prefix = AttributeFiltering::ActiveRecordFilterQueryBuilder.quote_column_path(query: query, prefix: column_prefix, column_name: info[:attribute])
|
|
46
46
|
order_clause = Arel.sql(ActiveRecord::Base.sanitize_sql_array("#{quoted_prefix} #{direction}"))
|
|
47
47
|
query = query.order(order_clause)
|
|
48
|
+
# Add a select for any order clause (unless we're already selecting *), as latest MySQL versions require it for DISTINCT queries
|
|
49
|
+
query = query.select(quoted_prefix) unless query.select_values.empty?
|
|
48
50
|
end
|
|
49
51
|
query
|
|
50
52
|
end
|
|
@@ -89,7 +89,7 @@ module Praxis
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def default(spec)
|
|
92
|
-
unless spec.is_a?(Hash) && spec.keys.size == 1 && %i[by page].include?(spec.keys.first)
|
|
92
|
+
unless spec.is_a?(::Hash) && spec.keys.size == 1 && %i[by page].include?(spec.keys.first)
|
|
93
93
|
raise "'default' syntax for pagination takes exactly one key specification. Either by: <:fieldname> or page: <num>" \
|
|
94
94
|
"#{spec} is invalid"
|
|
95
95
|
end
|
|
@@ -101,7 +101,7 @@ module Praxis
|
|
|
101
101
|
|
|
102
102
|
{ by: value }
|
|
103
103
|
when :page
|
|
104
|
-
raise "Error setting default pagination. Initial page should be a integer (but got #{value})" unless value.is_a?(Integer)
|
|
104
|
+
raise "Error setting default pagination. Initial page should be a integer (but got #{value})" unless value.is_a?(::Integer)
|
|
105
105
|
raise 'Cannot define a default pagination that is page-based, if page-based pagination is disallowed.' if target.defaults[:disallow_paging]
|
|
106
106
|
|
|
107
107
|
{ page: value }
|
|
@@ -67,19 +67,17 @@ module Praxis
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def _join_foreign_key_for(assoc_reflection)
|
|
70
|
-
|
|
71
|
-
if maj >= 6 && min >= 1
|
|
70
|
+
if ActiveRecord.gem_version >= Gem::Version.new('6.1')
|
|
72
71
|
assoc_reflection.join_foreign_key.to_sym
|
|
73
|
-
else
|
|
72
|
+
else # below 6.1
|
|
74
73
|
assoc_reflection.join_keys.foreign_key.to_sym
|
|
75
74
|
end
|
|
76
75
|
end
|
|
77
76
|
|
|
78
77
|
def _join_primary_key_for(assoc_reflection)
|
|
79
|
-
|
|
80
|
-
if maj >= 6 && min >= 1
|
|
78
|
+
if ActiveRecord.gem_version >= Gem::Version.new('6.1')
|
|
81
79
|
assoc_reflection.join_primary_key.to_sym
|
|
82
|
-
else
|
|
80
|
+
else # below 6.1
|
|
83
81
|
assoc_reflection.join_keys.key.to_sym
|
|
84
82
|
end
|
|
85
83
|
end
|
|
@@ -45,7 +45,7 @@ module Praxis
|
|
|
45
45
|
# @see Attributor::Model#load
|
|
46
46
|
def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, recurse: false, **options)
|
|
47
47
|
case value
|
|
48
|
-
when String
|
|
48
|
+
when ::String
|
|
49
49
|
return nil if value.blank?
|
|
50
50
|
|
|
51
51
|
base, *parameters = value.split(PARAMETER_SEPARATOR)
|
|
@@ -66,7 +66,7 @@ module Praxis
|
|
|
66
66
|
else
|
|
67
67
|
obj.type = 'application'
|
|
68
68
|
obj.subtype = base.split(WORD_SEPARATOR, 2).first
|
|
69
|
-
obj.suffix = String.new
|
|
69
|
+
obj.suffix = ::String.new
|
|
70
70
|
obj.parameters = {}
|
|
71
71
|
end
|
|
72
72
|
obj
|
|
@@ -126,7 +126,7 @@ module Praxis
|
|
|
126
126
|
# @return [String] canonicalized representation of the media type including all suffixes and parameters
|
|
127
127
|
def to_s
|
|
128
128
|
# Our handcrafted media types consist of a rich chocolatey center
|
|
129
|
-
s = String.new("#{type}/#{subtype}")
|
|
129
|
+
s = ::String.new("#{type}/#{subtype}")
|
|
130
130
|
|
|
131
131
|
# coated in a hard candy shell
|
|
132
132
|
s << '+' << suffix unless suffix.empty?
|
|
@@ -204,7 +204,7 @@ module Praxis
|
|
|
204
204
|
obj.type = type
|
|
205
205
|
obj.subtype = subtype
|
|
206
206
|
target_suffix = suffix || self.suffix
|
|
207
|
-
obj.suffix = redundant_suffix(target_suffix) ? String.new : target_suffix
|
|
207
|
+
obj.suffix = redundant_suffix(target_suffix) ? ::String.new : target_suffix
|
|
208
208
|
obj.parameters = self.parameters.merge(parameters)
|
|
209
209
|
|
|
210
210
|
obj
|
|
@@ -219,13 +219,13 @@ module Praxis
|
|
|
219
219
|
hash[:part_name] = { type: name_type.describe(true) }
|
|
220
220
|
|
|
221
221
|
unless shallow
|
|
222
|
-
hash[:attributes] = {} if attributes.keys.any? { |name| name.is_a? String }
|
|
222
|
+
hash[:attributes] = {} if attributes.keys.any? { |name| name.is_a? ::String }
|
|
223
223
|
hash[:pattern_attributes] = {} if attributes.keys.any? { |name| name.is_a? Regexp }
|
|
224
224
|
|
|
225
225
|
if hash.key?(:attributes) || hash.key?(:pattern_attributes)
|
|
226
226
|
describe_attributes(shallow, example: example).each do |name, sub_hash|
|
|
227
227
|
case name
|
|
228
|
-
when String
|
|
228
|
+
when ::String
|
|
229
229
|
hash[:attributes][name] = sub_hash
|
|
230
230
|
when Regexp
|
|
231
231
|
hash[:pattern_attributes][name.source] = sub_hash
|
|
@@ -305,7 +305,7 @@ module Praxis
|
|
|
305
305
|
return self << part
|
|
306
306
|
elsif self.class.options[:case_insensitive_load]
|
|
307
307
|
name = self.class.attributes.keys.find do |k|
|
|
308
|
-
k.is_a?(String) && key.downcase == k.downcase
|
|
308
|
+
k.is_a?(::String) && key.downcase == k.downcase
|
|
309
309
|
end
|
|
310
310
|
if name
|
|
311
311
|
part.name = name
|
data/lib/praxis/version.rb
CHANGED
data/praxis.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.executables << 'praxis'
|
|
24
24
|
|
|
25
25
|
spec.add_dependency 'activesupport', '>= 3'
|
|
26
|
-
spec.add_dependency 'attributor', '>=
|
|
26
|
+
spec.add_dependency 'attributor', '>= 7.0'
|
|
27
27
|
spec.add_dependency 'mime', '~> 0'
|
|
28
28
|
spec.add_dependency 'mustermann', '>=1.1'
|
|
29
29
|
spec.add_dependency 'rack', '>= 1'
|
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
|
|
|
32
32
|
|
|
33
33
|
spec.add_development_dependency 'bundler'
|
|
34
34
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
|
35
|
+
spec.add_development_dependency "appraisal"
|
|
35
36
|
|
|
36
37
|
if RUBY_PLATFORM !~ /java/
|
|
37
38
|
spec.add_development_dependency 'pry'
|
|
@@ -50,7 +51,4 @@ Gem::Specification.new do |spec|
|
|
|
50
51
|
spec.add_development_dependency 'rspec', '~> 3'
|
|
51
52
|
spec.add_development_dependency 'rspec-collection_matchers', '~> 1'
|
|
52
53
|
spec.add_development_dependency 'rspec-its', '~> 1'
|
|
53
|
-
# Just for the query selector extensions etc...
|
|
54
|
-
spec.add_development_dependency 'activerecord', '> 4', '< 7'
|
|
55
|
-
spec.add_development_dependency 'sequel', '~> 5'
|
|
56
54
|
end
|
|
@@ -7,6 +7,280 @@ describe Praxis::Blueprint do
|
|
|
7
7
|
|
|
8
8
|
its(:family) { should eq('hash') }
|
|
9
9
|
|
|
10
|
+
# This context might seem a duplication of tests that should be covered by the underlying attributor gem
|
|
11
|
+
# but while it is in structure, it is different because we're doing it with Blueprints (not Attributor Models)
|
|
12
|
+
# to make sure our Blueprints are behaving as expected.
|
|
13
|
+
context 'type resolution, option inheritance for attributes with and without references' do
|
|
14
|
+
# Overall strategy
|
|
15
|
+
# 1) When no type is specified:
|
|
16
|
+
# 1.1) if it is a leaf (no block)
|
|
17
|
+
# 1.1.1) with an reference with an attr with the same name
|
|
18
|
+
# - type copied from reference
|
|
19
|
+
# - reference options are inherited as well (and can be overridden by local attribute ones)
|
|
20
|
+
# 1.1.2) without a ref (or the ref does not have same attribute name)
|
|
21
|
+
# - Fail. Cannot determine type
|
|
22
|
+
# 1.2) if it has a block
|
|
23
|
+
# 1.2.1) with an reference with an attr with the same name
|
|
24
|
+
# - We assume you're re/defining a new Struct (or Struct[]), and we will incorporate the reference type
|
|
25
|
+
# for the matching name in case you are indeed redefining a subset of the attributes, so you can enjoy inheritance
|
|
26
|
+
# 1.2.2) without a ref (or the ref does not have same attribute name)
|
|
27
|
+
# - defaulted to Struct (if you meant Collection.of(Struct) things would fail later somehow)
|
|
28
|
+
# - options are NOT inherited at all (This is something we should ponder more about)
|
|
29
|
+
# 2) When type is specified:
|
|
30
|
+
# 2.1) if it is a leaf (no block)
|
|
31
|
+
# - ignore ref if there is one (with or without matching attribute name).
|
|
32
|
+
# - simply use provided type, and provided options (no inheritance)
|
|
33
|
+
# 2.2) if it has a block
|
|
34
|
+
# - Same as above: use type and options provided, ignore ref if there is one (with or without matching attribute name).
|
|
35
|
+
|
|
36
|
+
let(:mytype) do
|
|
37
|
+
Praxis::Blueprint.finalize!
|
|
38
|
+
Class.new(Praxis::Blueprint, &myblock).tap{|c| c._finalize!}
|
|
39
|
+
end
|
|
40
|
+
context 'with no explicit type specified' do
|
|
41
|
+
context 'without a block (if it is a leaf)' do
|
|
42
|
+
context 'that has a reference with an attribute with the same name' do
|
|
43
|
+
let(:myblock) {
|
|
44
|
+
Proc.new do
|
|
45
|
+
attributes reference: PersonBlueprint do
|
|
46
|
+
attribute :age, required: true, min: 42
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
it 'uses type from reference' do
|
|
51
|
+
expect(mytype.attributes).to have_key(:age)
|
|
52
|
+
expect(mytype.attributes[:age].type).to eq(PersonBlueprint.attributes[:age].type)
|
|
53
|
+
end
|
|
54
|
+
it 'copies over reference options and allows the attribute to override/add some' do
|
|
55
|
+
merged_options = PersonBlueprint.attributes[:age].options.merge(required: true, min: 42)
|
|
56
|
+
expect(mytype.attributes[:age].options).to include(merged_options)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
context 'with a reference, but that does not have a matching attribute name' do
|
|
60
|
+
let(:myblock) {
|
|
61
|
+
Proc.new do
|
|
62
|
+
attributes reference: AddressBlueprint do
|
|
63
|
+
attribute :age
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
}
|
|
67
|
+
it 'fails resolving' do
|
|
68
|
+
expect{mytype.attributes}.to raise_error(/Type for attribute with name: age could not be determined./)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
context 'without a reference' do
|
|
72
|
+
let(:myblock) {
|
|
73
|
+
Proc.new do
|
|
74
|
+
attributes do
|
|
75
|
+
attribute :age
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
}
|
|
79
|
+
it 'fails resolving' do
|
|
80
|
+
expect{mytype.attributes}.to raise_error(/Type for attribute with name: age could not be determined./)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
context 'with block (if it is NOT a leaf)' do
|
|
85
|
+
context 'that has a reference with an attribute with the same name' do
|
|
86
|
+
context 'which is not a collection type' do
|
|
87
|
+
let(:myblock) {
|
|
88
|
+
Proc.new do
|
|
89
|
+
attributes reference: PersonBlueprint do
|
|
90
|
+
attribute :age , description: 'I am fully redefining' do
|
|
91
|
+
attribute :foobar, Integer, min: 42
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
}
|
|
96
|
+
it 'picks Struct, and makes sure to pass the reference of the attribute along' do
|
|
97
|
+
expect(mytype.attributes).to have_key(:age)
|
|
98
|
+
age_attribute = mytype.attributes[:age]
|
|
99
|
+
# Resolves to Struct
|
|
100
|
+
expect(age_attribute.type).to be < Attributor::Struct
|
|
101
|
+
# does NOT brings any ref options (except the right reference)
|
|
102
|
+
expect(age_attribute.options).to include(description: 'I am fully redefining')
|
|
103
|
+
# Yes, there is no way we can ever use an Integer when we're defining a Struct...but if the parent was a Struct, we would
|
|
104
|
+
expect(age_attribute.options).to include(reference: Attributor::Integer)
|
|
105
|
+
# And the nested attribute is correctly resolved as well, and ensures options are there
|
|
106
|
+
expect(age_attribute.type.attributes[:foobar].type).to eq(Attributor::Integer)
|
|
107
|
+
expect(age_attribute.type.attributes[:foobar].options).to eq(min: 42)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
context 'which is a collection type' do
|
|
111
|
+
let(:myblock) {
|
|
112
|
+
Proc.new do
|
|
113
|
+
attributes reference: PersonBlueprint do
|
|
114
|
+
attribute :prior_addresses , description: 'I am fully redefining' do
|
|
115
|
+
attribute :street, required: true
|
|
116
|
+
attribute :new_attribute, String, default: 'foo'
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
}
|
|
121
|
+
it 'picks Struct, and makes sure to pass the reference of the attribute along' do
|
|
122
|
+
expect(mytype.attributes).to have_key(:prior_addresses)
|
|
123
|
+
prior_addresses_attribute = mytype.attributes[:prior_addresses]
|
|
124
|
+
# Resolves to Struct[]
|
|
125
|
+
expect(prior_addresses_attribute.type).to be < Attributor::Collection
|
|
126
|
+
expect(prior_addresses_attribute.type.member_type).to be < Attributor::Struct
|
|
127
|
+
# does NOT brings any ref options (except the right reference)
|
|
128
|
+
expect(prior_addresses_attribute.options).to include(description: 'I am fully redefining')
|
|
129
|
+
# Yes, there is no way we can ever use an Integer when we're defining a Struct...but if the parent was a Struct, we would
|
|
130
|
+
expect(prior_addresses_attribute.options).to include(reference: PersonBlueprint.attributes[:prior_addresses].type.member_type)
|
|
131
|
+
# And the nested attributes are correctly resolved as well, and ensures options are there
|
|
132
|
+
street_options_from_ref = PersonBlueprint.attributes[:prior_addresses].type.member_type.attributes[:street].options
|
|
133
|
+
expect(prior_addresses_attribute.type.member_type.attributes[:street].type).to eq(Attributor::String)
|
|
134
|
+
expect(prior_addresses_attribute.type.member_type.attributes[:street].options).to eq(street_options_from_ref.merge(required: true))
|
|
135
|
+
|
|
136
|
+
expect(prior_addresses_attribute.type.member_type.attributes[:new_attribute].type).to eq(Attributor::String)
|
|
137
|
+
expect(prior_addresses_attribute.type.member_type.attributes[:new_attribute].options).to eq(default: 'foo')
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
context 'in the unlikely case that the reference type has an anonymous Struct (or collection of)' do
|
|
141
|
+
let(:myblock) {
|
|
142
|
+
Proc.new do
|
|
143
|
+
attributes reference: PersonBlueprint do
|
|
144
|
+
attribute :funny_attribute, description: 'Funny business' do
|
|
145
|
+
attribute :foobar, Integer, min: 42
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
}
|
|
150
|
+
it 'correctly inherits it (same result as defaulting to Struct) and brings in the reference' do
|
|
151
|
+
expect(mytype.attributes).to have_key(:funny_attribute)
|
|
152
|
+
# Resolves to Struct, and brings (and merges) the ref options with the attribute's
|
|
153
|
+
expect(mytype.attributes[:funny_attribute].type).to be < Attributor::Struct
|
|
154
|
+
merged_options = {reference: PersonBlueprint.attributes[:funny_attribute].type}.merge(description: 'Funny business')
|
|
155
|
+
expect(mytype.attributes[:funny_attribute].options).to include(merged_options)
|
|
156
|
+
# And the nested attribute is correctly resolved as well, and ensures options are there
|
|
157
|
+
expect(mytype.attributes[:funny_attribute].type.attributes[:foobar].type).to eq(Attributor::Integer)
|
|
158
|
+
expect(mytype.attributes[:funny_attribute].type.attributes[:foobar].options).to eq(min: 42)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
context 'with a reference, but that does not have a matching attribute name' do
|
|
163
|
+
let(:myblock) {
|
|
164
|
+
Proc.new do
|
|
165
|
+
attributes reference: AddressBlueprint do
|
|
166
|
+
attribute :age, description: 'I am redefining' do
|
|
167
|
+
attribute :foobar, Integer, min: 42
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
}
|
|
172
|
+
it 'correctly defaults to Struct uses only the local options (same exact as if it had no reference)' do
|
|
173
|
+
expect(mytype.attributes).to have_key(:age)
|
|
174
|
+
age_attribute = mytype.attributes[:age]
|
|
175
|
+
# Resolves to Struct
|
|
176
|
+
expect(age_attribute.type).to be < Attributor::Struct
|
|
177
|
+
# does NOT brings any ref options
|
|
178
|
+
expect(age_attribute.options).to eq(description: 'I am redefining')
|
|
179
|
+
# And the nested attribute is correctly resolved as well, and ensures options are there
|
|
180
|
+
expect(age_attribute.type.attributes[:foobar].type).to eq(Attributor::Integer)
|
|
181
|
+
expect(age_attribute.type.attributes[:foobar].options).to eq(min: 42)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
context 'without a reference' do
|
|
185
|
+
let(:myblock) {
|
|
186
|
+
Proc.new do
|
|
187
|
+
attributes do
|
|
188
|
+
attribute :age, description: 'I am redefining' do
|
|
189
|
+
attribute :foobar, Integer, min: 42
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
}
|
|
194
|
+
it 'correctly defaults to Struct uses only the local options' do
|
|
195
|
+
expect(mytype.attributes).to have_key(:age)
|
|
196
|
+
age_attribute = mytype.attributes[:age]
|
|
197
|
+
# Resolves to Struct
|
|
198
|
+
expect(age_attribute.type).to be < Attributor::Struct
|
|
199
|
+
# does NOT brings any ref options
|
|
200
|
+
expect(age_attribute.options).to eq(description: 'I am redefining')
|
|
201
|
+
# And the nested attribute is correctly resolved as well, and ensures options are there
|
|
202
|
+
expect(age_attribute.type.attributes[:foobar].type).to eq(Attributor::Integer)
|
|
203
|
+
expect(age_attribute.type.attributes[:foobar].options).to eq(min: 42)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
context 'with an explicit type specified' do
|
|
209
|
+
context 'without a reference' do
|
|
210
|
+
let(:myblock) {
|
|
211
|
+
Proc.new do
|
|
212
|
+
attributes do
|
|
213
|
+
attribute :age, String, description: 'I am a String now'
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
}
|
|
217
|
+
it 'always uses the provided type and local options specified' do
|
|
218
|
+
expect(mytype.attributes).to have_key(:age)
|
|
219
|
+
age_attribute = mytype.attributes[:age]
|
|
220
|
+
# Resolves to String
|
|
221
|
+
expect(age_attribute.type).to eq(Attributor::String)
|
|
222
|
+
# copies local options
|
|
223
|
+
expect(age_attribute.options).to eq(description: 'I am a String now')
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
context 'with a reference' do
|
|
227
|
+
let(:myblock) {
|
|
228
|
+
Proc.new do
|
|
229
|
+
attributes reference: PersonBlueprint do
|
|
230
|
+
attribute :age, String, description: 'I am a String now'
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
}
|
|
234
|
+
it 'always uses the provided type and local options specified (same as if it had no reference)' do
|
|
235
|
+
expect(mytype.attributes).to have_key(:age)
|
|
236
|
+
age_attribute = mytype.attributes[:age]
|
|
237
|
+
# Resolves to String
|
|
238
|
+
expect(age_attribute.type).to eq(Attributor::String)
|
|
239
|
+
# copies local options
|
|
240
|
+
expect(age_attribute.options).to eq(description: 'I am a String now')
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
context 'with a reference, which can further percolate down' do
|
|
245
|
+
let(:myblock) {
|
|
246
|
+
Proc.new do
|
|
247
|
+
attributes reference: PersonBlueprint do
|
|
248
|
+
attribute :age, String, description: 'I am a String now'
|
|
249
|
+
attribute :address, Struct, description: 'Address subset' do
|
|
250
|
+
attribute :street, required: true
|
|
251
|
+
end
|
|
252
|
+
attribute :tags
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
it 'brings the child reference for address so we can redefine it' do
|
|
258
|
+
expect(mytype.attributes.keys).to eq([:age, :address, :tags])
|
|
259
|
+
age_attribute = mytype.attributes[:age]
|
|
260
|
+
expect(age_attribute.type).to eq(Attributor::String)
|
|
261
|
+
expect(age_attribute.options).to eq(description: 'I am a String now')
|
|
262
|
+
|
|
263
|
+
address_attribute = mytype.attributes[:address]
|
|
264
|
+
expect(address_attribute.type).to be < Attributor::Struct
|
|
265
|
+
# It brings in our local options AND percolates down the reference type for address
|
|
266
|
+
expect(address_attribute.options).to include(description: 'Address subset', reference: AddressBlueprint)
|
|
267
|
+
|
|
268
|
+
# Address fields are properly resolved to match the corresponding AddressBlueprint
|
|
269
|
+
expect(address_attribute.type.attributes.keys).to eq([:street])
|
|
270
|
+
street_attribute = address_attribute.type.attributes[:street]
|
|
271
|
+
expect(street_attribute.type).to eq(AddressBlueprint.attributes[:street].type)
|
|
272
|
+
# Makes sure our local options on the street are kept
|
|
273
|
+
expect(street_attribute.options).to include(required: true)
|
|
274
|
+
# And brings in other options from the inherited street attribute
|
|
275
|
+
expect(street_attribute.options).to include(description: 'The street')
|
|
276
|
+
|
|
277
|
+
# It also properly resolves the direct tags attribute from the reference, pointing to the same type
|
|
278
|
+
tags_attribute = mytype.attributes[:tags]
|
|
279
|
+
expect(tags_attribute.type).to eq PersonBlueprint.attributes[:tags].type
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
10
284
|
context 'deterministic examples' do
|
|
11
285
|
it 'works' do
|
|
12
286
|
person1 = PersonBlueprint.example('person 1')
|
|
@@ -75,7 +349,7 @@ describe Praxis::Blueprint do
|
|
|
75
349
|
end
|
|
76
350
|
|
|
77
351
|
it 'has an inner Struct class for the attributes' do
|
|
78
|
-
expect(blueprint_class.attribute.type).to be blueprint_class::
|
|
352
|
+
expect(blueprint_class.attribute.type).to be blueprint_class::InnerStruct
|
|
79
353
|
end
|
|
80
354
|
|
|
81
355
|
context 'an instance' do
|
|
@@ -221,22 +495,23 @@ describe Praxis::Blueprint do
|
|
|
221
495
|
end
|
|
222
496
|
end
|
|
223
497
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
end
|
|
498
|
+
# TODO: Think about this 'feature' ...
|
|
499
|
+
# context 'with a provided :reference option on attributes' do
|
|
500
|
+
# context 'that does not match the value set on the class' do
|
|
501
|
+
# subject(:mismatched_reference) do
|
|
502
|
+
# Class.new(Praxis::Blueprint) do
|
|
503
|
+
# self.reference = Class.new(Praxis::Blueprint)
|
|
504
|
+
# attributes(reference: Class.new(Praxis::Blueprint)) {}
|
|
505
|
+
# end
|
|
506
|
+
# end
|
|
507
|
+
|
|
508
|
+
# it 'should raise an error' do
|
|
509
|
+
# expect do
|
|
510
|
+
# mismatched_reference.attributes
|
|
511
|
+
# end.to raise_error(/Reference mismatch/)
|
|
512
|
+
# end
|
|
513
|
+
# end
|
|
514
|
+
# end
|
|
240
515
|
|
|
241
516
|
context '.example' do
|
|
242
517
|
context 'with some attribute values provided' do
|
|
@@ -154,6 +154,34 @@ describe Praxis::Extensions::Pagination::ActiveRecordPaginationHandler do
|
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
end
|
|
157
|
+
context 'adds SELECT fields when necessary' do
|
|
158
|
+
let(:order_params) { book_ordering_params_attribute.load(op) }
|
|
159
|
+
context 'when query comes with SELECT *' do
|
|
160
|
+
let(:query) { ActiveBook.includes(:author) }
|
|
161
|
+
let(:op) { '-writer.books.name' }
|
|
162
|
+
it 'does not add any specific SELECT' do
|
|
163
|
+
expect(subject.all.select_values).to be_empty
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
context 'when query comes with some SELECT fields' do
|
|
167
|
+
let(:query) { ActiveBook.includes(:author).select('simple_name') }
|
|
168
|
+
context 'with one ordering field' do
|
|
169
|
+
let(:op) { '-writer.books.name' }
|
|
170
|
+
it 'adds the field to SELECT (and keeps the original one)' do
|
|
171
|
+
expect(subject.all.select_values).to include('"/author/books"."simple_name"')
|
|
172
|
+
expect(subject.all.select_values).to include('simple_name')
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
context 'with multiple ordering fields' do
|
|
176
|
+
let(:op) { '-writer.books.name,author.id' }
|
|
177
|
+
it 'adds both fields to SELECT (and keeps the original one)' do
|
|
178
|
+
expect(subject.all.select_values).to include('"/author/books"."simple_name"')
|
|
179
|
+
expect(subject.all.select_values).to include('"/author"."id"')
|
|
180
|
+
expect(subject.all.select_values).to include('simple_name')
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
157
185
|
end
|
|
158
186
|
|
|
159
187
|
context '.association_info_for' do
|
|
@@ -5,10 +5,12 @@ class PersonBlueprint < Praxis::Blueprint
|
|
|
5
5
|
attribute :name, String, example: /[:first_name:]/
|
|
6
6
|
attribute :email, String, example: proc { |person| "#{person.name}@example.com" }
|
|
7
7
|
|
|
8
|
-
attribute :age, Integer
|
|
8
|
+
attribute :age, Integer, min: 0
|
|
9
|
+
# Weird, anonymous attribute built for specs only
|
|
10
|
+
attribute :funny_attribute, Struct, allow_extra: true
|
|
9
11
|
|
|
10
12
|
attribute :full_name, FullName
|
|
11
|
-
attribute :aliases,
|
|
13
|
+
attribute :aliases, FullName[]
|
|
12
14
|
|
|
13
15
|
attribute :address, AddressBlueprint, null: true, example: proc { |person, context| AddressBlueprint.example(context, resident: person) }
|
|
14
16
|
attribute :work_address, AddressBlueprint, null: true
|
|
@@ -19,7 +21,7 @@ class PersonBlueprint < Praxis::Blueprint
|
|
|
19
21
|
attribute :mother, String
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
attribute :tags, Attributor::
|
|
24
|
+
attribute :tags, Attributor::String[]
|
|
23
25
|
attribute :href, String
|
|
24
26
|
attribute :alive, Attributor::Boolean, default: true
|
|
25
27
|
attribute :myself, PersonBlueprint, null: true
|
|
@@ -44,7 +46,7 @@ class AddressBlueprint < Praxis::Blueprint
|
|
|
44
46
|
attributes do
|
|
45
47
|
attribute :id, Integer
|
|
46
48
|
attribute :name, String
|
|
47
|
-
attribute :street, String
|
|
49
|
+
attribute :street, String, description: 'The street'
|
|
48
50
|
attribute :state, String, values: %w[OR CA]
|
|
49
51
|
|
|
50
52
|
attribute :resident, PersonBlueprint, example: proc { |address, context| PersonBlueprint.example(context, address: address) }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: praxis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.pre.
|
|
4
|
+
version: 2.0.pre.33
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Josep M. Blanquer
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2023-05-
|
|
12
|
+
date: 2023-05-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activesupport
|
|
@@ -31,14 +31,14 @@ dependencies:
|
|
|
31
31
|
requirements:
|
|
32
32
|
- - ">="
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '
|
|
34
|
+
version: '7.0'
|
|
35
35
|
type: :runtime
|
|
36
36
|
prerelease: false
|
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
39
|
- - ">="
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: '
|
|
41
|
+
version: '7.0'
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: mime
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -137,6 +137,20 @@ dependencies:
|
|
|
137
137
|
- - ">="
|
|
138
138
|
- !ruby/object:Gem::Version
|
|
139
139
|
version: 12.3.3
|
|
140
|
+
- !ruby/object:Gem::Dependency
|
|
141
|
+
name: appraisal
|
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
type: :development
|
|
148
|
+
prerelease: false
|
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '0'
|
|
140
154
|
- !ruby/object:Gem::Dependency
|
|
141
155
|
name: pry
|
|
142
156
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -319,40 +333,6 @@ dependencies:
|
|
|
319
333
|
- - "~>"
|
|
320
334
|
- !ruby/object:Gem::Version
|
|
321
335
|
version: '1'
|
|
322
|
-
- !ruby/object:Gem::Dependency
|
|
323
|
-
name: activerecord
|
|
324
|
-
requirement: !ruby/object:Gem::Requirement
|
|
325
|
-
requirements:
|
|
326
|
-
- - ">"
|
|
327
|
-
- !ruby/object:Gem::Version
|
|
328
|
-
version: '4'
|
|
329
|
-
- - "<"
|
|
330
|
-
- !ruby/object:Gem::Version
|
|
331
|
-
version: '7'
|
|
332
|
-
type: :development
|
|
333
|
-
prerelease: false
|
|
334
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
335
|
-
requirements:
|
|
336
|
-
- - ">"
|
|
337
|
-
- !ruby/object:Gem::Version
|
|
338
|
-
version: '4'
|
|
339
|
-
- - "<"
|
|
340
|
-
- !ruby/object:Gem::Version
|
|
341
|
-
version: '7'
|
|
342
|
-
- !ruby/object:Gem::Dependency
|
|
343
|
-
name: sequel
|
|
344
|
-
requirement: !ruby/object:Gem::Requirement
|
|
345
|
-
requirements:
|
|
346
|
-
- - "~>"
|
|
347
|
-
- !ruby/object:Gem::Version
|
|
348
|
-
version: '5'
|
|
349
|
-
type: :development
|
|
350
|
-
prerelease: false
|
|
351
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
352
|
-
requirements:
|
|
353
|
-
- - "~>"
|
|
354
|
-
- !ruby/object:Gem::Version
|
|
355
|
-
version: '5'
|
|
356
336
|
description:
|
|
357
337
|
email:
|
|
358
338
|
- blanquer@gmail.com
|
|
@@ -368,6 +348,7 @@ files:
|
|
|
368
348
|
- ".ruby-version"
|
|
369
349
|
- ".simplecov"
|
|
370
350
|
- ".travis.yml"
|
|
351
|
+
- Appraisals
|
|
371
352
|
- CHANGELOG.md
|
|
372
353
|
- CONTRIBUTING.md
|
|
373
354
|
- Gemfile
|
|
@@ -378,6 +359,10 @@ files:
|
|
|
378
359
|
- Rakefile
|
|
379
360
|
- SELECTOR_NOTES.txt
|
|
380
361
|
- bin/praxis
|
|
362
|
+
- gemfiles/active_6.gemfile
|
|
363
|
+
- gemfiles/active_6.gemfile.lock
|
|
364
|
+
- gemfiles/active_7.gemfile
|
|
365
|
+
- gemfiles/active_7.gemfile.lock
|
|
381
366
|
- lib/praxis.rb
|
|
382
367
|
- lib/praxis/action_definition.rb
|
|
383
368
|
- lib/praxis/action_definition/headers_dsl_compiler.rb
|