apipie-bindings 0.0.12 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/doc/release_notes.md +5 -0
- data/lib/apipie_bindings/action.rb +45 -27
- data/lib/apipie_bindings/api.rb +2 -1
- data/lib/apipie_bindings/exceptions.rb +12 -2
- data/lib/apipie_bindings/param.rb +1 -7
- data/lib/apipie_bindings/version.rb +1 -1
- data/test/dummy/app/controllers/users_controller.rb +9 -0
- data/test/unit/action_test.rb +72 -15
- data/test/unit/api_test.rb +8 -0
- data/test/unit/data/dummy.json +1 -1
- metadata +4 -5
- data/lib/apipie_bindings/utilities.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e406c65a2e7c642745b62120655b24b3877383a4
|
4
|
+
data.tar.gz: ce5b76ee3599b53c5434baf1e4b160ca1d38304c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01d3a63b169f4c8ffcd0e205f141695e46a1582d7fb9d993539012b9f45126db549f08df61d9a6d82e91ea772da994794f351ab8326b0992b7d83f51d2179fc0
|
7
|
+
data.tar.gz: c04f40471e23fd22c16215d0d0a91f90df2e621627bbd8b2fd1854758838f500bf566391727f54df481af4da7692385eb4683ae4e5fa7b96f2ada55cc5427ebf
|
data/doc/release_notes.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
Release notes
|
2
2
|
=============
|
3
3
|
|
4
|
+
### 0.0.13 (2015-04-23)
|
5
|
+
* Limited rest-client versionto < 1.8.0
|
6
|
+
* Added option to turn off param validation (per call)
|
7
|
+
* Validation of optional parameters containing required attributes ([#24](https://github.com/Apipie/apipie-bindings/issues/24), [#25](https://github.com/Apipie/apipie-bindings/issues/25))
|
8
|
+
|
4
9
|
### 0.0.12 (2015-03-23)
|
5
10
|
* Add readme to the dummy app
|
6
11
|
* Fix ordering issue in tests
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'apipie_bindings/utilities'
|
2
|
-
|
3
1
|
module ApipieBindings
|
4
2
|
|
5
3
|
class Action
|
@@ -57,35 +55,56 @@ module ApipieBindings
|
|
57
55
|
return suitable_route
|
58
56
|
end
|
59
57
|
|
60
|
-
def validate!(
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
def validate!(parameters)
|
59
|
+
errors = validate(params, parameters)
|
60
|
+
|
61
|
+
missing_arguments, errors = errors.partition { |e| e.kind == :missing_argument }
|
62
|
+
missing_arguments.map! { |e| e.argument }
|
63
|
+
raise ApipieBindings::MissingArgumentsError.new(missing_arguments) unless missing_arguments.empty?
|
64
|
+
|
65
|
+
invalid_types, errors = errors.partition { |e| e.kind == :invalid_type }
|
66
|
+
invalid_types.map! { |e| [e.argument, e.details] }
|
67
|
+
raise ApipieBindings::InvalidArgumentTypesError.new(invalid_types) unless invalid_types.empty?
|
68
|
+
|
69
|
+
errors.map! { |e| e.argument }
|
70
|
+
raise ApipieBindings::ValidationError.new(errors) unless errors.empty?
|
67
71
|
end
|
68
72
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
def validate(params, values, path=nil)
|
74
|
+
return [ErrorData.new(:invalid_type, path, 'Hash')] unless values.respond_to?(:keys)
|
75
|
+
# check required
|
76
|
+
required_keys = params.select(&:required?).map(&:name)
|
77
|
+
given_keys = values.keys.select { |par| !values[par].nil? }.map(&:to_s)
|
78
|
+
missing_params = required_keys - given_keys
|
79
|
+
errors = missing_params.map { |p| ErrorData.new(:missing_argument, add_to_path(path, p)) }
|
80
|
+
|
81
|
+
# check individuals one by one
|
82
|
+
values.each do |param, value|
|
83
|
+
param_description = params.find { |p| p.name == param.to_s }
|
84
|
+
if param_description
|
85
|
+
|
86
|
+
# nested?
|
87
|
+
if !param_description.params.empty? && !value.nil?
|
88
|
+
# array
|
89
|
+
if param_description.expected_type == :array
|
90
|
+
value.each.with_index do |item, i|
|
91
|
+
errors += validate(param_description.params, item, add_to_path(path, param_description.name, i))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
# hash
|
95
|
+
if param_description.expected_type == :hash
|
96
|
+
errors += validate(param_description.params, value, add_to_path(path, param_description.name))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
74
100
|
end
|
101
|
+
|
102
|
+
errors
|
75
103
|
end
|
76
104
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
if required_param.is_a?(Hash)
|
81
|
-
key = required_param.keys.first
|
82
|
-
slave_hash = slave.select { |p| p.is_a?(Hash) && p[key] }
|
83
|
-
missing << missing_params(required_param[key], slave_hash.first ? slave_hash.first[key] : [])
|
84
|
-
else
|
85
|
-
missing << required_param unless slave.include?(required_param)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
missing.flatten.sort
|
105
|
+
def add_to_path(path, *additions)
|
106
|
+
path ||= ''
|
107
|
+
additions.inject(path) { |new_path, add| new_path.empty? ? "#{add}" : "#{new_path}[#{add}]" }
|
89
108
|
end
|
90
109
|
|
91
110
|
def to_s
|
@@ -95,6 +114,5 @@ module ApipieBindings
|
|
95
114
|
def inspect
|
96
115
|
to_s
|
97
116
|
end
|
98
|
-
|
99
117
|
end
|
100
118
|
end
|
data/lib/apipie_bindings/api.rb
CHANGED
@@ -148,6 +148,7 @@ module ApipieBindings
|
|
148
148
|
# @param [Hash] options options to influence the how the call is processed
|
149
149
|
# * *:response* (Symbol) *:raw* - skip parsing JSON in response
|
150
150
|
# * *:with_authentication* (Bool) *true* - use rest client with/without auth configuration
|
151
|
+
# * *:skip_validation* (Bool) *false* - skip validation of parameters
|
151
152
|
# @example show user data
|
152
153
|
# call(:users, :show, :id => 1)
|
153
154
|
def call(resource_name, action_name, params={}, headers={}, options={})
|
@@ -155,7 +156,7 @@ module ApipieBindings
|
|
155
156
|
resource = resource(resource_name)
|
156
157
|
action = resource.action(action_name)
|
157
158
|
route = action.find_route(params)
|
158
|
-
action.validate!(params)
|
159
|
+
action.validate!(params) unless options[:skip_validation]
|
159
160
|
options[:fake_response] = find_match(fake_responses, resource_name, action_name, params) || action.examples.first if dry_run?
|
160
161
|
return http_call(
|
161
162
|
route.method,
|
@@ -3,17 +3,27 @@ module ApipieBindings
|
|
3
3
|
class ConfigurationError < StandardError; end
|
4
4
|
class DocLoadingError < StandardError; end
|
5
5
|
|
6
|
-
|
6
|
+
ErrorData = Struct.new(:kind, :argument, :details)
|
7
|
+
|
8
|
+
class ValidationError < StandardError
|
7
9
|
attr_reader :params
|
8
10
|
|
9
11
|
def initialize(params)
|
10
12
|
@params = params
|
11
13
|
end
|
14
|
+
end
|
12
15
|
|
16
|
+
class InvalidArgumentTypesError < ValidationError
|
13
17
|
def to_s
|
14
|
-
"#{
|
18
|
+
preformated = params.map { |p| "#{p[0]} - #{p[1]} was expected" }
|
19
|
+
"#{super}: #{preformated.join(', ')}"
|
15
20
|
end
|
21
|
+
end
|
16
22
|
|
23
|
+
class MissingArgumentsError < ValidationError
|
24
|
+
def to_s
|
25
|
+
"#{super}: #{params.join(', ')}"
|
26
|
+
end
|
17
27
|
end
|
18
28
|
|
19
29
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'apipie_bindings/utilities'
|
2
|
-
|
3
1
|
module ApipieBindings
|
4
2
|
|
5
3
|
class Param
|
@@ -13,14 +11,10 @@ module ApipieBindings
|
|
13
11
|
@params = params.map { |p| ApipieBindings::Param.new(p) }
|
14
12
|
@expected_type = param[:expected_type].to_sym
|
15
13
|
@description = param[:description].gsub(/<\/?[^>]+?>/, "")
|
16
|
-
@required = param[:required]
|
14
|
+
@required = !!param[:required]
|
17
15
|
@validator = param[:validator]
|
18
16
|
end
|
19
17
|
|
20
|
-
def tree(&block)
|
21
|
-
ApipieBindings::Utilities.params_hash_tree(@params, &block)
|
22
|
-
end
|
23
|
-
|
24
18
|
def required?
|
25
19
|
@required
|
26
20
|
end
|
@@ -14,6 +14,15 @@ EXAMPLE
|
|
14
14
|
api!
|
15
15
|
param :user, Hash do
|
16
16
|
param :name, String, required: true
|
17
|
+
param :vip, :bool
|
18
|
+
param :address, Hash do
|
19
|
+
param :city, String, required: true
|
20
|
+
param :street, String
|
21
|
+
end
|
22
|
+
param :contacts, Array do
|
23
|
+
param :contact, String, required: true
|
24
|
+
param :kind, String
|
25
|
+
end
|
17
26
|
end
|
18
27
|
def create
|
19
28
|
super
|
data/test/unit/action_test.rb
CHANGED
@@ -41,22 +41,79 @@ describe ApipieBindings::Action do
|
|
41
41
|
# incuded params in alphanumeric order.
|
42
42
|
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
44
|
+
describe "validate!" do
|
45
|
+
it "should raise on missing required params" do
|
46
|
+
e = proc do
|
47
|
+
resource.action(:create).validate!({ :user => { :vip => true } })
|
48
|
+
end.must_raise(ApipieBindings::MissingArgumentsError)
|
49
|
+
e.message.must_match /: user\[name\]$/
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should raise on missing nested required params (hash)" do
|
53
|
+
e = proc do
|
54
|
+
resource.action(:create).validate!({
|
55
|
+
:user => {
|
56
|
+
:name => 'Jogn Doe',
|
57
|
+
:address => {
|
58
|
+
:street => 'K JZD'
|
59
|
+
}
|
60
|
+
}
|
61
|
+
})
|
62
|
+
end.must_raise(ApipieBindings::MissingArgumentsError)
|
63
|
+
e.message.must_match /: user\[address\]\[city\]$/
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise on missing nested required params (array)" do
|
67
|
+
e = proc do
|
68
|
+
resource.action(:create).validate!({
|
69
|
+
:user => {
|
70
|
+
:name => 'Jogn Doe',
|
71
|
+
:contacts => [
|
72
|
+
{:kind => 'email'},
|
73
|
+
]
|
74
|
+
}
|
75
|
+
})
|
76
|
+
end.must_raise(ApipieBindings::MissingArgumentsError)
|
77
|
+
e.message.must_match /: user\[contacts\]\[0\]\[contact\]$/
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should raise on invalid param format" do
|
81
|
+
e = proc do
|
82
|
+
resource.action(:create).validate!({
|
83
|
+
:user => {
|
84
|
+
:name => 'Jogn Doe',
|
85
|
+
:contacts => [
|
86
|
+
1,
|
87
|
+
2
|
88
|
+
]
|
89
|
+
}
|
90
|
+
})
|
91
|
+
end.must_raise(ApipieBindings::InvalidArgumentTypesError)
|
92
|
+
e.message.must_match /user\[contacts\]\[0\] - Hash was expected/
|
93
|
+
e.message.must_match /user\[contacts\]\[1\] - Hash was expected/
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should accept minimal correct params" do
|
97
|
+
resource.action(:create).validate!({:user => { :name => 'John Doe' } })
|
98
|
+
resource.action(:create_unnested).validate!(:name => "John Doe")
|
99
|
+
end
|
56
100
|
|
57
|
-
|
58
|
-
|
59
|
-
|
101
|
+
it "should accept full correct params" do
|
102
|
+
resource.action(:create).validate!({
|
103
|
+
:user => {
|
104
|
+
:name => 'John Doe',
|
105
|
+
:vip => true,
|
106
|
+
:address => {
|
107
|
+
:city => 'Ankh-Morpork',
|
108
|
+
:street => 'Audit Alley'
|
109
|
+
},
|
110
|
+
:contacts => [
|
111
|
+
{:contact => 'john@doe.org', :kind => 'email'},
|
112
|
+
{:contact => '123456', :kind => 'pobox'}
|
113
|
+
]
|
114
|
+
}
|
115
|
+
})
|
116
|
+
end
|
60
117
|
end
|
61
118
|
|
62
119
|
it "should have name visible in puts" do
|
data/test/unit/api_test.rb
CHANGED
@@ -24,6 +24,14 @@ describe ApipieBindings::API do
|
|
24
24
|
api.call(:users, :index, params, headers)
|
25
25
|
end
|
26
26
|
|
27
|
+
it "should call the method and skip param validation on demand" do
|
28
|
+
params = { :user => { :vip => true } }
|
29
|
+
headers = { :content_type => 'application/json' }
|
30
|
+
options = { :skip_validation => true }
|
31
|
+
ApipieBindings::API.any_instance.expects(:http_call).with('post', '/users', params, headers, options)
|
32
|
+
api.call(:users, :create, params, headers, options)
|
33
|
+
end
|
34
|
+
|
27
35
|
it "should call the method and fill in the params" do
|
28
36
|
params = { :id => 1 }
|
29
37
|
headers = { :content_type => 'application/json' }
|
data/test/unit/data/dummy.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"docs":{"name":"Dummy","info":"Another API description","copyright":null,"doc_url":"./apipie/1.0","api_url":"/","resources":{"
|
1
|
+
{"docs":{"name":"Dummy","info":"Another API description","copyright":null,"doc_url":"./apipie/1.0","api_url":"/","resources":{"posts":{"doc_url":"./apipie/1.0/posts","api_url":"/","name":"Posts","short_description":null,"full_description":null,"version":"1.0","formats":null,"metadata":null,"methods":[{"doc_url":"./apipie/1.0/posts/index","name":"index","apis":[{"api_url":"/users/:user_id/posts","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/posts/show","name":"show","apis":[{"api_url":"/users/:user_id/posts/:id","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/posts/create","name":"create","apis":[{"api_url":"/users/:user_id/posts","http_method":"POST","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/posts/update","name":"update","apis":[{"api_url":"/users/:user_id/posts/:id","http_method":"PATCH","short_description":null,"deprecated":null},{"api_url":"/users/:user_id/posts/:id","http_method":"PUT","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/posts/destroy","name":"destroy","apis":[{"api_url":"/users/:user_id/posts/:id","http_method":"DELETE","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]}]},"users":{"doc_url":"./apipie/1.0/users","api_url":"/","name":"Users","short_description":null,"full_description":null,"version":"1.0","formats":null,"metadata":null,"methods":[{"doc_url":"./apipie/1.0/users/index","name":"index","apis":[{"api_url":"/users","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":["GET /users\n200\n[ {\"user\":{\"name\":\"John Doe\" }} ]\n"],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/users/show","name":"show","apis":[{"api_url":"/users/:id","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/users/create","name":"create","apis":[{"api_url":"/users","http_method":"POST","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[{"name":"user","full_name":"user","description":"","required":false,"allow_nil":false,"validator":"Must be a Hash","expected_type":"hash","metadata":null,"show":true,"params":[{"name":"name","full_name":"user[name]","description":"","required":true,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true},{"name":"vip","full_name":"user[vip]","description":"","required":false,"allow_nil":false,"validator":"Must be 'true' or 'false'","expected_type":"boolean","metadata":null,"show":true},{"name":"address","full_name":"user[address]","description":"","required":false,"allow_nil":false,"validator":"Must be a Hash","expected_type":"hash","metadata":null,"show":true,"params":[{"name":"city","full_name":"user[address][city]","description":"","required":true,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true},{"name":"street","full_name":"user[address][street]","description":"","required":false,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true}]},{"name":"contacts","full_name":"user[contacts]","description":"","required":false,"allow_nil":false,"validator":"Must be an Array of nested elements","expected_type":"array","metadata":null,"show":true,"params":[{"name":"contact","full_name":"user[contacts][contact]","description":"","required":true,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true},{"name":"kind","full_name":"user[contacts][kind]","description":"","required":false,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true}]}]}],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/users/update","name":"update","apis":[{"api_url":"/users/:id","http_method":"PATCH","short_description":null,"deprecated":null},{"api_url":"/users/:id","http_method":"PUT","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/users/destroy","name":"destroy","apis":[{"api_url":"/users/:id","http_method":"DELETE","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/users/create_unnested","name":"create_unnested","apis":[{"api_url":"/users/create_unnested","http_method":"POST","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[{"name":"name","full_name":"name","description":"","required":true,"allow_nil":false,"validator":"Must be String","expected_type":"string","metadata":null,"show":true}],"examples":[],"metadata":null,"see":[]}]},"comments":{"doc_url":"./apipie/1.0/comments","api_url":"/","name":"Comments","short_description":null,"full_description":null,"version":"1.0","formats":null,"metadata":null,"methods":[{"doc_url":"./apipie/1.0/comments/index","name":"index","apis":[{"api_url":"/users/:user_id/posts/:post_id/comments","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/comments/show","name":"show","apis":[{"api_url":"/users/:user_id/posts/:post_id/comments/:id","http_method":"GET","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/comments/create","name":"create","apis":[{"api_url":"/users/:user_id/posts/:post_id/comments","http_method":"POST","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/comments/update","name":"update","apis":[{"api_url":"/users/:user_id/posts/:post_id/comments/:id","http_method":"PATCH","short_description":null,"deprecated":null},{"api_url":"/users/:user_id/posts/:post_id/comments/:id","http_method":"PUT","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]},{"doc_url":"./apipie/1.0/comments/destroy","name":"destroy","apis":[{"api_url":"/users/:user_id/posts/:post_id/comments/:id","http_method":"DELETE","short_description":null,"deprecated":null}],"formats":null,"full_description":"","errors":[],"params":[],"examples":[],"metadata":null,"see":[]}]}},"link_extension":".html"}}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apipie-bindings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Bačovský
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: 1.6.5
|
34
34
|
- - <
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 1.8.0
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: 1.6.5
|
44
44
|
- - <
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 1.8.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: oauth
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -201,7 +201,6 @@ files:
|
|
201
201
|
- lib/apipie_bindings/resource.rb
|
202
202
|
- lib/apipie_bindings/rest_client_oauth.rb
|
203
203
|
- lib/apipie_bindings/route.rb
|
204
|
-
- lib/apipie_bindings/utilities.rb
|
205
204
|
- lib/apipie_bindings/version.rb
|
206
205
|
- test/dummy/.gitignore
|
207
206
|
- test/dummy/Gemfile
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module ApipieBindings
|
2
|
-
|
3
|
-
module Utilities
|
4
|
-
|
5
|
-
def self.params_hash_tree(params_hash, &block)
|
6
|
-
block ||= lambda { |_| true }
|
7
|
-
params_hash.inject([]) do |tree, par|
|
8
|
-
if block.call(par)
|
9
|
-
subtree = par.expected_type == :hash ? { par.name => par.tree(&block) } : par.name
|
10
|
-
tree << subtree
|
11
|
-
end
|
12
|
-
tree
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|