moonrope 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/moonrope/action.rb +6 -4
- data/lib/moonrope/authenticator.rb +3 -0
- data/lib/moonrope/base.rb +17 -0
- data/lib/moonrope/dsl/authenticator_dsl.rb +4 -0
- data/lib/moonrope/dsl/structure_dsl.rb +1 -0
- data/lib/moonrope/rack_middleware.rb +50 -36
- data/lib/moonrope/request.rb +1 -1
- data/lib/moonrope/structure.rb +24 -6
- data/lib/moonrope/structure_attribute.rb +24 -0
- data/lib/moonrope/version.rb +1 -1
- data/templates/basic/_action_form.erb +66 -66
- data/templates/basic/assets/try.js +8 -2
- data/templates/basic/authenticator.erb +1 -0
- data/templates/basic/layout.erb +3 -3
- data/test/tests/rack_middleware_test.rb +8 -0
- data/test/tests/structures_test.rb +55 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec14194988474a3b6e4e0d3e40ffafb64a3fb4c1
|
4
|
+
data.tar.gz: 968649b6047917e0713c0510ed32d2c66d4265d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbda03f158543eb581faf08fe4954ce4ac567bf03017e0e33dcef295da04b28d262eaa0038facc3e8c62e84f42fdd79f41580e571ba01a659a335c0ff564a1bf
|
7
|
+
data.tar.gz: 64e355f2ef7a89bd545e951070737d2668de5a38c60013b1355c2277a4f0b02318e4d0e7223bd675e2a5364d2d1f9c887b30c3fb3730b9c170c8eddbaf432058
|
data/lib/moonrope/action.rb
CHANGED
@@ -107,19 +107,21 @@ module Moonrope
|
|
107
107
|
# Execute a block of code and catch approprite Moonrope errors and return
|
108
108
|
# a result.
|
109
109
|
#
|
110
|
-
def convert_errors_to_action_result(&block)
|
110
|
+
def convert_errors_to_action_result(start_time = nil, &block)
|
111
111
|
begin
|
112
112
|
yield block
|
113
113
|
rescue => exception
|
114
114
|
case exception
|
115
115
|
when Moonrope::Errors::RequestError
|
116
116
|
result = ActionResult.new(self)
|
117
|
+
result.time = start_time ? (Time.now - start_time).round(2) : nil
|
117
118
|
result.status = exception.status
|
118
119
|
result.data = exception.data
|
119
120
|
result
|
120
121
|
else
|
121
122
|
if error_block = @controller.base.external_errors[exception.class]
|
122
123
|
result = ActionResult.new(self)
|
124
|
+
result.time = start_time ? (Time.now - start_time).round(2) : nil
|
123
125
|
error_block.call(exception, result)
|
124
126
|
result
|
125
127
|
else
|
@@ -149,14 +151,14 @@ module Moonrope
|
|
149
151
|
#
|
150
152
|
eval_environment.default_params = self.default_params
|
151
153
|
|
152
|
-
|
154
|
+
start_time = Time.now
|
155
|
+
|
156
|
+
convert_errors_to_action_result(start_time) do
|
153
157
|
#
|
154
158
|
# Validate the parameters
|
155
159
|
#
|
156
160
|
self.validate_parameters(eval_environment.params)
|
157
161
|
|
158
|
-
start_time = Time.now
|
159
|
-
|
160
162
|
# Run before filters
|
161
163
|
controller.before_actions_for(name).each do |action|
|
162
164
|
eval_environment.instance_eval(&action.block)
|
@@ -17,6 +17,9 @@ module Moonrope
|
|
17
17
|
# @return [Symbol] the name of the authenticator
|
18
18
|
attr_reader :name
|
19
19
|
|
20
|
+
# @return [String] the friendly name for the authenticator
|
21
|
+
attr_accessor :friendly_name
|
22
|
+
|
20
23
|
# @return [String] the description for the authenticator
|
21
24
|
attr_accessor :description
|
22
25
|
|
data/lib/moonrope/base.rb
CHANGED
@@ -61,6 +61,23 @@ module Moonrope
|
|
61
61
|
@dsl.instance_eval(&block) if block_given?
|
62
62
|
end
|
63
63
|
|
64
|
+
#
|
65
|
+
# Make a new base based on configuration
|
66
|
+
#
|
67
|
+
def copy_from(other)
|
68
|
+
@environment = other.environment
|
69
|
+
@load_directories = other.load_directories
|
70
|
+
@on_request = other.on_request
|
71
|
+
other.request_error_callbacks.each { |block| self.register_request_error_callback(&block) }
|
72
|
+
other.external_errors.each { |error, block| self.register_external_error(error, &block) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def copy
|
76
|
+
new_base = self.class.new
|
77
|
+
new_base.copy_from(self)
|
78
|
+
new_base
|
79
|
+
end
|
80
|
+
|
64
81
|
#
|
65
82
|
# Reset the whole base to contain no data.
|
66
83
|
#
|
@@ -77,6 +77,7 @@ module Moonrope
|
|
77
77
|
attribute.value = options[:value]
|
78
78
|
attribute.example = options[:eg] || options[:example]
|
79
79
|
attribute.doc = options[:doc]
|
80
|
+
attribute.mutation = options[:mutation]
|
80
81
|
attribute.groups = @groups
|
81
82
|
attribute.conditions = @conditions
|
82
83
|
@structure.attributes[type] << attribute
|
@@ -25,23 +25,6 @@ module Moonrope
|
|
25
25
|
#
|
26
26
|
def call(env)
|
27
27
|
if env['PATH_INFO'] =~ Moonrope::Request.path_regex
|
28
|
-
|
29
|
-
if @options[:reload_on_each_request]
|
30
|
-
@base.load
|
31
|
-
end
|
32
|
-
|
33
|
-
#
|
34
|
-
# Call the on request block if one has been defined for the base.
|
35
|
-
#
|
36
|
-
if @base.on_request.is_a?(Proc)
|
37
|
-
@base.on_request.call(@base, env)
|
38
|
-
end
|
39
|
-
|
40
|
-
#
|
41
|
-
# Create a new request object
|
42
|
-
#
|
43
|
-
request = @base.request(env, $1)
|
44
|
-
|
45
28
|
#
|
46
29
|
# Set some global headers which are always returned
|
47
30
|
#
|
@@ -65,6 +48,32 @@ module Moonrope
|
|
65
48
|
#
|
66
49
|
global_headers['Content-Type'] = 'application/json'
|
67
50
|
|
51
|
+
#
|
52
|
+
# Reload if needed
|
53
|
+
#
|
54
|
+
if @options[:reload_on_each_request]
|
55
|
+
base = @base.copy
|
56
|
+
begin
|
57
|
+
base.load
|
58
|
+
rescue => e
|
59
|
+
return generate_error_triplet(@base, e, global_headers)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
base = @base
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Call the on request block if one has been defined for the base.
|
67
|
+
#
|
68
|
+
if base.on_request.is_a?(Proc)
|
69
|
+
base.on_request.call(base, env)
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Create a new request object
|
74
|
+
#
|
75
|
+
request = base.request(env, $1)
|
76
|
+
|
68
77
|
#
|
69
78
|
# Check the request is valid
|
70
79
|
#
|
@@ -78,30 +87,13 @@ module Moonrope
|
|
78
87
|
begin
|
79
88
|
result = request.execute
|
80
89
|
json = result.to_json
|
90
|
+
Moonrope.logger.info "[#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}] controller=#{request.controller.name} action=#{request.action.name} status=#{result.status} time=#{result.time} ip=#{request.ip} size=#{json.bytesize}"
|
81
91
|
global_headers['Content-Length'] = json.bytesize.to_s
|
82
92
|
[200, global_headers.merge(result.headers), [json]]
|
83
93
|
rescue JSON::ParserError => e
|
84
94
|
[400, global_headers, [{:status => 'invalid-json', :details => e.message}.to_json]]
|
85
95
|
rescue => e
|
86
|
-
|
87
|
-
Moonrope.logger.info e.message
|
88
|
-
Moonrope.logger.info e.backtrace.join("\n")
|
89
|
-
|
90
|
-
response = {:status => 'internal-server-error'}
|
91
|
-
|
92
|
-
# Call any request errors which have been registered on the base
|
93
|
-
@base.request_error_callbacks.each do |callback|
|
94
|
-
callback.call(request, e)
|
95
|
-
end
|
96
|
-
|
97
|
-
# If in development, return more details about the exception which was raised.
|
98
|
-
if @base.environment == 'development'
|
99
|
-
response[:error] = e.class.to_s
|
100
|
-
response[:message] = e.message
|
101
|
-
response[:backtrace] = e.backtrace[0,6]
|
102
|
-
end
|
103
|
-
|
104
|
-
[500, global_headers, [response.to_json]]
|
96
|
+
generate_error_triplet(base, e, global_headers)
|
105
97
|
end
|
106
98
|
|
107
99
|
else
|
@@ -113,5 +105,27 @@ module Moonrope
|
|
113
105
|
end
|
114
106
|
end
|
115
107
|
|
108
|
+
def generate_error_triplet(base, exception, headers = {})
|
109
|
+
Moonrope.logger.info exception.class
|
110
|
+
Moonrope.logger.info exception.message
|
111
|
+
Moonrope.logger.info exception.backtrace.join("\n")
|
112
|
+
|
113
|
+
response = {:status => 'internal-server-error'}
|
114
|
+
|
115
|
+
# Call any request errors which have been registered on the base
|
116
|
+
base.request_error_callbacks.each do |callback|
|
117
|
+
callback.call(request, exception)
|
118
|
+
end
|
119
|
+
|
120
|
+
# If in development, return more details about the exception which was raised.
|
121
|
+
if base.environment == 'development'
|
122
|
+
response[:error] = exception.class.to_s
|
123
|
+
response[:message] = exception.message
|
124
|
+
response[:backtrace] = exception.backtrace[0,6]
|
125
|
+
end
|
126
|
+
|
127
|
+
[500, headers, [response.to_json]]
|
128
|
+
end
|
129
|
+
|
116
130
|
end
|
117
131
|
end
|
data/lib/moonrope/request.rb
CHANGED
@@ -120,7 +120,7 @@ module Moonrope
|
|
120
120
|
#
|
121
121
|
def params
|
122
122
|
@params ||= begin
|
123
|
-
if @env['CONTENT_TYPE']
|
123
|
+
if @env['CONTENT_TYPE'] && @env['CONTENT_TYPE'] =~ /\Aapplication\/json(;|\z)/i
|
124
124
|
Moonrope::ParamSet.new(rack_request.body.read)
|
125
125
|
else
|
126
126
|
Moonrope::ParamSet.new(rack_request.params['params'])
|
data/lib/moonrope/structure.rb
CHANGED
@@ -85,13 +85,29 @@ module Moonrope
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
+
if options[:attributes]
|
89
|
+
hash.reject! { |k,v| !options[:attributes].include?(k.to_sym) }
|
90
|
+
end
|
91
|
+
|
88
92
|
# Add expansions
|
89
93
|
if options[:expansions]
|
90
94
|
|
95
|
+
if options[:expansions].is_a?(Array)
|
96
|
+
expansions_to_include = options[:expansions].each_with_object({}) do |expan, hash|
|
97
|
+
if expan.is_a?(Symbol) || expan.is_a?(String)
|
98
|
+
hash[expan.to_sym] = {}
|
99
|
+
elsif expan.is_a?(Hash)
|
100
|
+
hash[expan.first.first.to_sym] = expan.first.last
|
101
|
+
end
|
102
|
+
end
|
103
|
+
else
|
104
|
+
expansions_to_include = true
|
105
|
+
end
|
106
|
+
|
91
107
|
# Add structured expansions
|
92
108
|
@attributes[:expansion].each do |attribute|
|
93
|
-
next if
|
94
|
-
DeepMerge.deep_merge! hash_for_attributes([attribute], object, environment), hash
|
109
|
+
next if expansions_to_include.is_a?(Hash) && !expansions_to_include.keys.include?(attribute.name.to_sym)
|
110
|
+
DeepMerge.deep_merge! hash_for_attributes([attribute], object, environment, :structure_opts => expansions_to_include.is_a?(Hash) && expansions_to_include[attribute.name.to_sym]), hash
|
95
111
|
end
|
96
112
|
|
97
113
|
# Add the expansions
|
@@ -162,7 +178,7 @@ module Moonrope
|
|
162
178
|
#
|
163
179
|
# Return a returnable hash for a given set of structured fields.
|
164
180
|
#
|
165
|
-
def hash_for_attributes(attributes, object, environment)
|
181
|
+
def hash_for_attributes(attributes, object, environment, value_options = {})
|
166
182
|
return {} unless attributes.is_a?(Array)
|
167
183
|
Hash.new.tap do |hash|
|
168
184
|
attributes.each do |attribute|
|
@@ -180,9 +196,11 @@ module Moonrope
|
|
180
196
|
elsif attribute.value
|
181
197
|
value = attribute.value
|
182
198
|
else
|
183
|
-
value = value_for_attribute(object, environment, attribute)
|
199
|
+
value = value_for_attribute(object, environment, attribute, value_options)
|
184
200
|
end
|
185
201
|
|
202
|
+
value = attribute.mutate(value)
|
203
|
+
|
186
204
|
if attribute.groups.empty?
|
187
205
|
hash[attribute.name] = value
|
188
206
|
else
|
@@ -203,7 +221,7 @@ module Moonrope
|
|
203
221
|
#
|
204
222
|
# Return a value for a structured field.
|
205
223
|
#
|
206
|
-
def value_for_attribute(object, environment,
|
224
|
+
def value_for_attribute(object, environment, attribute, options = {})
|
207
225
|
if attribute.source_attribute.is_a?(Proc)
|
208
226
|
value = environment.instance_eval(&attribute.source_attribute)
|
209
227
|
else
|
@@ -214,7 +232,7 @@ module Moonrope
|
|
214
232
|
# If a structure is required, lookup the desired structure and set the
|
215
233
|
# hash value as appropriate.
|
216
234
|
if structure = self.base.structure(attribute.structure)
|
217
|
-
structure_opts = attribute.structure_opts || {}
|
235
|
+
structure_opts = options[:structure_opts] || attribute.structure_opts || {}
|
218
236
|
if value.respond_to?(:map)
|
219
237
|
value.map do |v|
|
220
238
|
structure.hash(v, structure_opts.merge(:request => environment.request))
|
@@ -12,6 +12,7 @@ module Moonrope
|
|
12
12
|
attr_accessor :value
|
13
13
|
attr_accessor :example
|
14
14
|
attr_accessor :doc
|
15
|
+
attr_accessor :mutation
|
15
16
|
|
16
17
|
def initialize(type, name)
|
17
18
|
@type = type
|
@@ -28,12 +29,35 @@ module Moonrope
|
|
28
29
|
([groups] + [name]).flatten.compact.join('.')
|
29
30
|
end
|
30
31
|
|
32
|
+
def mutate(value)
|
33
|
+
if mutation
|
34
|
+
value ? value.public_send(mutation) : nil
|
35
|
+
else
|
36
|
+
auto_mutate(value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def auto_mutate(value)
|
41
|
+
case value_type
|
42
|
+
when :timestamp
|
43
|
+
value.is_a?(Time) ? value.to_s : value
|
44
|
+
when :unix_timestamp
|
45
|
+
value.to_i
|
46
|
+
else
|
47
|
+
value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
31
51
|
def example
|
32
52
|
@example ||= begin
|
33
53
|
if value_type == :timestamp
|
34
54
|
"2016-12-25 09:42:00 +0000"
|
55
|
+
elsif value_type == :unix_timestamp
|
56
|
+
"1491070507"
|
35
57
|
elsif value_type == :boolean
|
36
58
|
"false"
|
59
|
+
elsif value_type == :uuid
|
60
|
+
"017dabc1-3f4f-47ab-ab7d-86e2ed0de679"
|
37
61
|
end
|
38
62
|
end
|
39
63
|
end
|
data/lib/moonrope/version.rb
CHANGED
@@ -1,77 +1,77 @@
|
|
1
|
-
|
2
|
-
<
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
<% unless host.nil? %>
|
2
|
+
<p class='tryFormActivate'><a class='tryFormActivate__button' href='#'>Try this request in your browser</a></p>
|
3
|
+
<form class='tryForm'>
|
4
|
+
<input type='hidden' name='controller' value='<%= controller.name %>'>
|
5
|
+
<input type='hidden' name='action' value='<%= action.name %>'>
|
6
|
+
<div class='tryForm__header'>
|
7
|
+
<input type='text' id='host' name='host' value='<%= host %>'>
|
8
|
+
/api/
|
9
|
+
<input type='text' id='version' name='version' value='v1' class='v'>
|
10
|
+
/<%= controller.name %>/<%= action.name %>
|
11
|
+
</div>
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
<% if action.authenticator_to_use.is_a?(Moonrope::Authenticator) %>
|
14
|
+
<p class='tryForm__heading'>Headers</p>
|
15
|
+
<table class='tryForm__table'>
|
16
|
+
<% for name, options in action.authenticator_to_use.headers %>
|
17
|
+
<tr>
|
18
|
+
<td width="50%"><code><%= name %></code></td>
|
19
|
+
<td width="50%"><input type='text' class='tryForm__tableField headerField' name='<%= name %>'></td>
|
20
|
+
</tr>
|
21
|
+
<% end %>
|
22
|
+
</table>
|
20
23
|
<% end %>
|
21
|
-
</table>
|
22
|
-
<% end %>
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
<% unless action.params.empty? %>
|
26
|
+
<p class='tryForm__heading'>Parameters</p>
|
27
|
+
<table class='tryForm__table'>
|
28
|
+
<% for name, param in action.params %>
|
29
|
+
<tr>
|
30
|
+
<td width="30%"><code><%= name %></code></td>
|
31
|
+
<td width="20%"><%= friendly_type param[:type] %></td>
|
32
|
+
<td width="50%"><input type='text' class='tryForm__tableField paramField' name='<%= name %>' placeholder='<%= param[:default] %>' data-type='<%= param[:type] %>'></td>
|
33
|
+
</tr>
|
34
|
+
<% end %>
|
35
|
+
</table>
|
33
36
|
<% end %>
|
34
|
-
</table>
|
35
|
-
<% end %>
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
<div class='tryForm__checkbox'>
|
45
|
-
<input type='checkbox' class='tryForm__fullAttrs' name='full' id="full_attrs" <% if action.includes_full_attributes? %>checked='checked'<%end%>>
|
46
|
-
<label for="full_attrs">Yes - include extended attributes</label>
|
47
|
-
</div>
|
48
|
-
</td>
|
49
|
-
</tr>
|
50
|
-
<% end %>
|
51
|
-
<% if action.can_change_expansions? %>
|
52
|
-
<tr>
|
53
|
-
<td width="50%">Include expansions?</td>
|
54
|
-
<td width="50%">
|
55
|
-
<% for expansion in action.available_expansions %>
|
38
|
+
<% if action.can_change_full? || action.can_change_expansions? %>
|
39
|
+
<p class='tryForm__heading'>Structures</p>
|
40
|
+
<table class='tryForm__table'>
|
41
|
+
<% if action.can_change_full? %>
|
42
|
+
<tr>
|
43
|
+
<td width="50%">Include extended attributes?</td>
|
44
|
+
<td width="50%">
|
56
45
|
<div class='tryForm__checkbox'>
|
57
|
-
<input type='checkbox' class='
|
58
|
-
<label for="
|
46
|
+
<input type='checkbox' class='tryForm__fullAttrs' name='full' id="full_attrs" <% if action.includes_full_attributes? %>checked='checked'<%end%>>
|
47
|
+
<label for="full_attrs">Yes - include extended attributes</label>
|
59
48
|
</div>
|
60
|
-
|
61
|
-
</
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
49
|
+
</td>
|
50
|
+
</tr>
|
51
|
+
<% end %>
|
52
|
+
<% if action.can_change_expansions? %>
|
53
|
+
<tr>
|
54
|
+
<td width="50%">Include expansions?</td>
|
55
|
+
<td width="50%">
|
56
|
+
<% for expansion in action.available_expansions %>
|
57
|
+
<div class='tryForm__checkbox'>
|
58
|
+
<input type='checkbox' class='tryForm__expansions' name='<%= expansion%>' id="expan_<%= expansion %>" <% if action.includes_expansion?(expansion) %>checked='checked'<%end%>>
|
59
|
+
<label for="expan_<%= expansion %>"><%= expansion %></label>
|
60
|
+
</div>
|
61
|
+
<% end %>
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
<% end %>
|
66
65
|
|
67
|
-
|
66
|
+
</table>
|
68
67
|
|
69
|
-
|
70
|
-
<button class='tryForm__buttonLink' type='submit'>Make this request</button>
|
71
|
-
<button class='tryForm__buttonLink tryFormCancel' type='button'>Cancel</button>
|
72
|
-
</p>
|
73
|
-
|
74
|
-
<pre class='tryForm__output'>The request output will be shown here...</pre>
|
75
|
-
</form>
|
68
|
+
<% end %>
|
76
69
|
|
70
|
+
<p class='tryForm__button'>
|
71
|
+
<button class='tryForm__buttonLink' type='submit'>Make this request</button>
|
72
|
+
<button class='tryForm__buttonLink tryFormCancel' type='button'>Cancel</button>
|
73
|
+
</p>
|
77
74
|
|
75
|
+
<pre class='tryForm__output'>The request output will be shown here...</pre>
|
76
|
+
</form>
|
77
|
+
<% end %>
|
@@ -97,11 +97,17 @@ $(document).ready(function() {
|
|
97
97
|
outputBox.text(JSON.stringify(data, null, 4))
|
98
98
|
outputBox.show()
|
99
99
|
},
|
100
|
-
error: function() {
|
100
|
+
error: function(xhr) {
|
101
101
|
// Errors which occurr aren't very well reported at the moment.
|
102
102
|
// They should be.
|
103
|
+
if(xhr.getResponseHeader('content-type') == 'application/json') {
|
104
|
+
var text = JSON.stringify(JSON.parse(xhr.responseText), null, 4)
|
105
|
+
} else {
|
106
|
+
var text = "Failed to make request."
|
107
|
+
}
|
108
|
+
|
103
109
|
outputBox.show()
|
104
|
-
outputBox.text(
|
110
|
+
outputBox.text(text)
|
105
111
|
outputBox.addClass('tryForm__output--error').removeClass('tryForm__output--success')
|
106
112
|
}
|
107
113
|
})
|
@@ -6,6 +6,7 @@
|
|
6
6
|
<% else %>
|
7
7
|
<% set_page_title "#{humanize(authenticator.name.to_s.capitalize)} Authenticator" %>
|
8
8
|
<h1><%= humanize(authenticator.name.to_s.capitalize) %> Authenticator</h1>
|
9
|
+
<% set_active_nav "authenticator-#{authenticator.name.to_s}" %>
|
9
10
|
<% end %>
|
10
11
|
|
11
12
|
<p class='text'>
|
data/templates/basic/layout.erb
CHANGED
@@ -17,10 +17,10 @@
|
|
17
17
|
Home
|
18
18
|
</a>
|
19
19
|
</li>
|
20
|
-
<%
|
20
|
+
<% base.authenticators.select { |k,v| v.friendly_name }.each do |id, authenticator| %>
|
21
21
|
<li>
|
22
|
-
<a href='<%= path('authenticators/
|
23
|
-
|
22
|
+
<a href='<%= path('authenticators/' + id.to_s) %>' class="<%= active_nav == "authenticator-" + id.to_s ? 'active' : '' %>">
|
23
|
+
<%= authenticator.friendly_name %>
|
24
24
|
</a>
|
25
25
|
</li>
|
26
26
|
<% end %>
|
@@ -68,6 +68,14 @@ class RackMiddlewareTest < Test::Unit::TestCase
|
|
68
68
|
assert_equal 'Adam', response_json['data']
|
69
69
|
end
|
70
70
|
|
71
|
+
def test_params_in_body_with_charset
|
72
|
+
post "/api/v1/users/echo", '{"name":"Adam"}', {'CONTENT_TYPE' => 'application/json; charset=utf8'}
|
73
|
+
assert_equal 200, last_response.status
|
74
|
+
assert response_json = JSON.parse(last_response.body)
|
75
|
+
assert_equal 'success', response_json['status']
|
76
|
+
assert_equal 'Adam', response_json['data']
|
77
|
+
end
|
78
|
+
|
71
79
|
def test_passing_invalid_json_renders_a_bad_request
|
72
80
|
get "/api/v1/users/list", {:params => "{invalidjson}"}
|
73
81
|
assert_equal 400, last_response.status
|
@@ -332,4 +332,59 @@ class StructuresTest < Test::Unit::TestCase
|
|
332
332
|
assert_equal "Bananas!", base.structure(:animal).attributes[:basic].select { |a| a.name == :example2 }.first.description
|
333
333
|
end
|
334
334
|
|
335
|
+
def test_mutating_values
|
336
|
+
base = Moonrope::Base.new do
|
337
|
+
structure :animal do
|
338
|
+
basic :name, :mutation => :downcase
|
339
|
+
end
|
340
|
+
end
|
341
|
+
assert_equal 'fido', base.structure(:animal).hash(Animal.new(:name => 'FIDO'))[:name]
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_auto_mutating_values
|
345
|
+
base = Moonrope::Base.new do
|
346
|
+
structure :animal do
|
347
|
+
basic :name, :type => :unix_timestamp
|
348
|
+
end
|
349
|
+
end
|
350
|
+
assert_equal 1234567890, base.structure(:animal).hash(Animal.new(:name => Time.at(1234567890)))[:name]
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_manually_selecting_attributes
|
354
|
+
base = Moonrope::Base.new do
|
355
|
+
structure :animal do
|
356
|
+
basic :id
|
357
|
+
basic :name
|
358
|
+
end
|
359
|
+
end
|
360
|
+
hash = base.structure(:animal).hash(Animal.new(:id => 12345, :name => "Fido"), :attributes => [:id])
|
361
|
+
assert_equal 12345, hash[:id]
|
362
|
+
assert_equal false, hash.has_key?(:name)
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
def test_setting_options_for_embedded_expansions
|
367
|
+
user = User.new(:id => 1, :username => 'dave')
|
368
|
+
animal1 = Animal.new(:id => 1, :name => 'Fido', :color => 'Ginger', :user => user)
|
369
|
+
animal2 = Animal.new(:id => 2, :name => 'Jess', :color => 'Black & White', :user => user)
|
370
|
+
user.animals << animal1
|
371
|
+
user.animals << animal2
|
372
|
+
|
373
|
+
base = Moonrope::Base.new do
|
374
|
+
structure :user do
|
375
|
+
basic { {:id => o.id, :username => o.username } }
|
376
|
+
expansion :animals, :structure => :animal
|
377
|
+
end
|
378
|
+
|
379
|
+
structure :animal do
|
380
|
+
basic :id
|
381
|
+
basic :name
|
382
|
+
full :color
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
hash = base.structure(:user).hash(user, :expansions => [{:animals => {:full => true}}])
|
387
|
+
assert_equal 'Ginger', hash[:animals][0][:color]
|
388
|
+
end
|
389
|
+
|
335
390
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moonrope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Cooke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -192,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
192
|
version: '0'
|
193
193
|
requirements: []
|
194
194
|
rubyforge_project:
|
195
|
-
rubygems_version: 2.
|
195
|
+
rubygems_version: 2.5.1
|
196
196
|
signing_key:
|
197
197
|
specification_version: 4
|
198
198
|
summary: An API server DSL.
|