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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5af89a4e614e26c289fad12a69304c7a2f293562
4
- data.tar.gz: e2db44de7655b8d4d3aa659fd814b1fdca6af522
3
+ metadata.gz: ec14194988474a3b6e4e0d3e40ffafb64a3fb4c1
4
+ data.tar.gz: 968649b6047917e0713c0510ed32d2c66d4265d9
5
5
  SHA512:
6
- metadata.gz: 90e9f623a0f62e3564fc9ba17850684f263810a04c707ff11765d12522ceef810d8524f8c93b8cc9b3a29e6a72663593552fe6050016c57c7ffe373128969d0c
7
- data.tar.gz: 1d661f3d8acc4352ecc936ccbbf42d18afbefcf128db5b993e0c3edd947b84b360af8b6864e21a974b12c29c44be50e04d233c83a46afe1cce7fbd6c62704e8f
6
+ metadata.gz: dbda03f158543eb581faf08fe4954ce4ac567bf03017e0e33dcef295da04b28d262eaa0038facc3e8c62e84f42fdd79f41580e571ba01a659a335c0ff564a1bf
7
+ data.tar.gz: 64e355f2ef7a89bd545e951070737d2668de5a38c60013b1355c2277a4f0b02318e4d0e7223bd675e2a5364d2d1f9c887b30c3fb3730b9c170c8eddbaf432058
@@ -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
- convert_errors_to_action_result do
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
 
@@ -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
  #
@@ -6,6 +6,10 @@ module Moonrope
6
6
  @authenticator = authenticator
7
7
  end
8
8
 
9
+ def friendly_name(value)
10
+ @authenticator.friendly_name = value
11
+ end
12
+
9
13
  def description(value)
10
14
  @authenticator.description = value
11
15
  end
@@ -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
- Moonrope.logger.info e.class
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
@@ -120,7 +120,7 @@ module Moonrope
120
120
  #
121
121
  def params
122
122
  @params ||= begin
123
- if @env['CONTENT_TYPE'] == 'application/json'
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'])
@@ -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 options[:expansions].is_a?(Array) && !options[:expansions].include?(attribute.name.to_sym)
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, attribute)
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
@@ -1,3 +1,3 @@
1
1
  module Moonrope
2
- VERSION = '2.0.0'
2
+ VERSION = '2.0.1'
3
3
  end
@@ -1,77 +1,77 @@
1
- <p class='tryFormActivate'><a class='tryFormActivate__button' href='#'>Try this request in your browser</a></p>
2
- <form class='tryForm'>
3
- <input type='hidden' name='controller' value='<%= controller.name %>'>
4
- <input type='hidden' name='action' value='<%= action.name %>'>
5
- <div class='tryForm__header'>
6
- <input type='text' id='host' name='host' value='<%= host %>'>
7
- /api/
8
- <input type='text' id='version' name='version' value='v1' class='v'>
9
- /<%= controller.name %>/<%= action.name %>
10
- </div>
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
- <% if action.authenticator_to_use.is_a?(Moonrope::Authenticator) %>
13
- <p class='tryForm__heading'>Headers</p>
14
- <table class='tryForm__table'>
15
- <% for name, options in action.authenticator_to_use.headers %>
16
- <tr>
17
- <td width="50%"><code><%= name %></code></td>
18
- <td width="50%"><input type='text' class='tryForm__tableField headerField' name='<%= name %>'></td>
19
- </tr>
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
- <% unless action.params.empty? %>
25
- <p class='tryForm__heading'>Parameters</p>
26
- <table class='tryForm__table'>
27
- <% for name, param in action.params %>
28
- <tr>
29
- <td width="30%"><code><%= name %></code></td>
30
- <td width="20%"><%= friendly_type param[:type] %></td>
31
- <td width="50%"><input type='text' class='tryForm__tableField paramField' name='<%= name %>' placeholder='<%= param[:default] %>' data-type='<%= param[:type] %>'></td>
32
- </tr>
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
- <% if action.can_change_full? || action.can_change_expansions? %>
38
- <p class='tryForm__heading'>Structures</p>
39
- <table class='tryForm__table'>
40
- <% if action.can_change_full? %>
41
- <tr>
42
- <td width="50%">Include extended attributes?</td>
43
- <td width="50%">
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='tryForm__expansions' name='<%= expansion%>' id="expan_<%= expansion %>" <% if action.includes_expansion?(expansion) %>checked='checked'<%end%>>
58
- <label for="expan_<%= expansion %>"><%= expansion %></label>
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
- <% end %>
61
- </td>
62
- </tr>
63
- <% end %>
64
-
65
- </table>
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
- <% end %>
66
+ </table>
68
67
 
69
- <p class='tryForm__button'>
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("Failed to make request.")
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'>
@@ -17,10 +17,10 @@
17
17
  Home
18
18
  </a>
19
19
  </li>
20
- <% if base.authenticators[:default] %>
20
+ <% base.authenticators.select { |k,v| v.friendly_name }.each do |id, authenticator| %>
21
21
  <li>
22
- <a href='<%= path('authenticators/default') %>' class="<%= active_nav == 'authenticator-default' ? 'active' : '' %>">
23
- Authentication
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.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: 2016-08-08 00:00:00.000000000 Z
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.4.5
195
+ rubygems_version: 2.5.1
196
196
  signing_key:
197
197
  specification_version: 4
198
198
  summary: An API server DSL.