yaji 0.3.5-x64-mingw32

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.
@@ -0,0 +1,84 @@
1
+ /*
2
+ * Copyright 2010, Lloyd Hilaiel.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in
13
+ * the documentation and/or other materials provided with the
14
+ * distribution.
15
+ *
16
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
17
+ * contributors may be used to endorse or promote products derived
18
+ * from this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ * POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+ #ifndef __YAJL_PARSER_H__
34
+ #define __YAJL_PARSER_H__
35
+
36
+ #include "api/yajl_parse.h"
37
+ #include "yajl_bytestack.h"
38
+ #include "yajl_buf.h"
39
+
40
+
41
+ typedef enum {
42
+ yajl_state_start = 0,
43
+ yajl_state_parse_complete,
44
+ yajl_state_parse_error,
45
+ yajl_state_lexical_error,
46
+ yajl_state_map_start,
47
+ yajl_state_map_sep,
48
+ yajl_state_map_need_val,
49
+ yajl_state_map_got_val,
50
+ yajl_state_map_need_key,
51
+ yajl_state_array_start,
52
+ yajl_state_array_got_val,
53
+ yajl_state_array_need_val
54
+ } yajl_state;
55
+
56
+ struct yajl_handle_t {
57
+ const yajl_callbacks * callbacks;
58
+ void * ctx;
59
+ yajl_lexer lexer;
60
+ const char * parseError;
61
+ /* the number of bytes consumed from the last client buffer,
62
+ * in the case of an error this will be an error offset, in the
63
+ * case of an error this can be used as the error offset */
64
+ unsigned int bytesConsumed;
65
+ /* temporary storage for decoded strings */
66
+ yajl_buf decodeBuf;
67
+ /* a stack of states. access with yajl_state_XXX routines */
68
+ yajl_bytestack stateStack;
69
+ /* memory allocation routines */
70
+ yajl_alloc_funcs alloc;
71
+ };
72
+
73
+ YAJL_API
74
+ yajl_status
75
+ yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
76
+ unsigned int jsonTextLen);
77
+
78
+ YAJL_API
79
+ unsigned char *
80
+ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
81
+ unsigned int jsonTextLen, int verbose);
82
+
83
+
84
+ #endif
@@ -0,0 +1,7 @@
1
+ #include "api/yajl_version.h"
2
+
3
+ int yajl_version(void)
4
+ {
5
+ return YAJL_VERSION;
6
+ }
7
+
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2011 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require "yaji/version"
21
+ require "parser_ext"
22
+
23
+ module YAJI
24
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2011 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module YAJI
21
+ VERSION = "0.3.5"
22
+ end
@@ -0,0 +1,80 @@
1
+ gem 'rake-compiler', '>= 0.7.5'
2
+ require "rake/extensiontask"
3
+
4
+ def gemspec
5
+ @clean_gemspec ||= eval(File.read(File.expand_path('../../yaji.gemspec', __FILE__)))
6
+ end
7
+
8
+ require 'rubygems/package_task'
9
+ Gem::PackageTask.new(gemspec) do |pkg|
10
+ pkg.need_tar = true
11
+ end
12
+
13
+ version_router = lambda do |t|
14
+ File.open(t.name, 'wb') do |f|
15
+ f.write <<-RUBY
16
+ require "yaji/\#{RUBY_VERSION.sub(/\\.\\d+$/, '')}/parser_ext"
17
+ RUBY
18
+ end
19
+ end
20
+
21
+ class Platform
22
+ attr_reader :name, :host, :versions
23
+
24
+ def initialize(params)
25
+ @name = params[:name]
26
+ @host = params[:host]
27
+ @versions = params[:versions]
28
+ end
29
+
30
+ def each_version
31
+ @versions.each do |v|
32
+ yield(v, v[/\d\.\d\.\d/])
33
+ end
34
+ end
35
+
36
+ def short_versions
37
+ res = []
38
+ each_version do |long, short|
39
+ res << short
40
+ end
41
+ res
42
+ end
43
+ end
44
+
45
+ recent = "2.0.0-p353"
46
+ CROSS_PLATFORMS = [
47
+ Platform.new(:name => 'x64-mingw32', :host => 'x86_64-w64-mingw32', :versions => %w(1.9.3-p484 2.0.0-p353 2.1.0)),
48
+ Platform.new(:name => 'x86-mingw32', :host => 'i686-w64-mingw32', :versions => %w(1.8.7-p374 1.9.3-p484 2.0.0-p353 2.1.0)),
49
+ ]
50
+ Rake::ExtensionTask.new("parser_ext", gemspec) do |ext|
51
+ ext.ext_dir = File.join('ext', 'yaji')
52
+
53
+ ext.cross_compile = true
54
+ ext.cross_platform = ENV['TARGET']
55
+ if ENV['RUBY_CC_VERSION']
56
+ ext.lib_dir = "lib/yaji"
57
+ end
58
+ ext.cross_compiling do |spec|
59
+ spec.files.delete("lib/yaji/parser_ext.so")
60
+ spec.files.push("lib/parser_ext.rb", Dir["lib/yaji/*/parser_ext.so"])
61
+ file "#{ext.tmp_dir}/#{ext.cross_platform}/stage/lib/parser_ext.rb", &version_router
62
+ end
63
+
64
+ # clean compiled extension
65
+ CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
66
+ end
67
+
68
+ file "lib/parser_ext.rb", &version_router
69
+ task :cross => "lib/parser_ext.rb"
70
+
71
+ desc "Package gem for windows"
72
+ task "package:windows" => :package do
73
+ CROSS_PLATFORMS.each do |platform|
74
+ ENV['TARGET'] = platform.name
75
+ platform.each_version do |long, short|
76
+ sh("env RUBY_CC_VERSION=#{short} RBENV_VERSION=#{long} rbenv exec rake cross compile")
77
+ end
78
+ sh("env RUBY_CC_VERSION=#{platform.short_versions.join(":")} RBENV_VERSION=#{recent} rbenv exec rake cross native gem")
79
+ end
80
+ end
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+ Rake::TestTask.new do |test|
3
+ test.libs << "test" << "."
4
+ test.ruby_opts << "-rruby-debug" if ENV['DEBUG']
5
+ test.pattern = 'test/test_*.rb'
6
+ test.verbose = true
7
+ end
@@ -0,0 +1,4 @@
1
+ desc 'Start an irb session and load the library.'
2
+ task :console do
3
+ exec "irb -I lib -rruby-debug -ryaji"
4
+ end
@@ -0,0 +1,47 @@
1
+ {
2
+ "total_rows": 4,
3
+ "offset": 0,
4
+ "rows": [
5
+ {
6
+ "id": "3e8ceb5873cf91fa418c2ab5a0000386",
7
+ "key": "3e8ceb5873cf91fa418c2ab5a0000386",
8
+ "value": {
9
+ "_id": "3e8ceb5873cf91fa418c2ab5a0000386",
10
+ "_rev": "1-967a00dff5e02add41819138abb3284d"
11
+ }
12
+ },
13
+ {
14
+ "id": "biking",
15
+ "key": "biking",
16
+ "value": {
17
+ "_id": "biking",
18
+ "_rev": "2-d4b43fd051e693a5191db2eaba89903c",
19
+ "title": "Biking2",
20
+ "body": "My biggest hobby is mountainbiking. The other day...",
21
+ "date": "2009/01/30 18:04:11"
22
+ }
23
+ },
24
+ {
25
+ "id": "bought-a-cat",
26
+ "key": "bought-a-cat",
27
+ "value": {
28
+ "_id": "bought-a-cat",
29
+ "_rev": "1-ccd0a7e95ade7eb2d29cc02ffa582b30",
30
+ "title": "Bought a Cat",
31
+ "body": "I went to the the pet store earlier and brought home a little kitty...",
32
+ "date": "2009/02/17 21:13:39"
33
+ }
34
+ },
35
+ {
36
+ "id": "hello-world",
37
+ "key": "hello-world",
38
+ "value": {
39
+ "_id": "hello-world",
40
+ "_rev": "1-97dd85b06c25328a300f3f4041def370",
41
+ "title": "Hello World",
42
+ "body": "Well hello and welcome to my new blog...",
43
+ "date": "2009/01/15 15:52:20"
44
+ }
45
+ }
46
+ ]
47
+ }
@@ -0,0 +1,370 @@
1
+ require 'minitest/autorun'
2
+ require 'yaji'
3
+ require 'curb'
4
+
5
+ class TestParser < MiniTest::Unit::TestCase
6
+
7
+ class Generator
8
+ def initialize(data, options = {})
9
+ @callback = nil
10
+ @options = {:chunk_size => 10}.merge(options)
11
+ @chunks = case data
12
+ when Array
13
+ data
14
+ when String
15
+ count = (data.bytesize / @options[:chunk_size].to_f).ceil
16
+ data.unpack("a#{@options[:chunk_size]}" * count)
17
+ end
18
+ end
19
+
20
+ def on_body
21
+ old = @callback
22
+ if block_given?
23
+ @callback = Proc.new
24
+ end
25
+ old
26
+ end
27
+
28
+ def perform
29
+ size = @options[:chunk_size]
30
+ if @callback
31
+ @chunks.each do |chunk|
32
+ @callback.call(chunk)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def test_it_generates_events
39
+ events = []
40
+ parser = YAJI::Parser.new(toys_json_str)
41
+ parser.parse do |p, e, v|
42
+ events << [p, e, v]
43
+ end
44
+ expected = [
45
+ ["", :start_hash, nil],
46
+ ["", :hash_key, "total_rows"],
47
+ ["/total_rows", :number, 2],
48
+ ["", :hash_key, "rows"],
49
+ ["/rows", :start_array, nil],
50
+ ["/rows/", :start_hash, nil],
51
+ ["/rows/", :hash_key, "id"],
52
+ ["/rows//id", :string, "buzz"],
53
+ ["/rows/", :hash_key, "props"],
54
+ ["/rows//props", :start_hash, nil],
55
+ ["/rows//props", :hash_key, "humanoid"],
56
+ ["/rows//props/humanoid", :boolean, true],
57
+ ["/rows//props", :hash_key, "armed"],
58
+ ["/rows//props/armed", :boolean, true],
59
+ ["/rows//props", :end_hash, nil],
60
+ ["/rows/", :hash_key, "movies"],
61
+ ["/rows//movies", :start_array, nil],
62
+ ["/rows//movies/", :number, 1],
63
+ ["/rows//movies/", :number, 2],
64
+ ["/rows//movies/", :number, 3],
65
+ ["/rows//movies", :end_array, nil],
66
+ ["/rows/", :end_hash, nil],
67
+ ["/rows/", :start_hash, nil],
68
+ ["/rows/", :hash_key, "id"],
69
+ ["/rows//id", :string, "barbie"],
70
+ ["/rows/", :hash_key, "props"],
71
+ ["/rows//props", :start_hash, nil],
72
+ ["/rows//props", :hash_key, "humanoid"],
73
+ ["/rows//props/humanoid", :boolean, true],
74
+ ["/rows//props", :hash_key, "armed"],
75
+ ["/rows//props/armed", :boolean, false],
76
+ ["/rows//props", :end_hash, nil],
77
+ ["/rows/", :hash_key, "movies"],
78
+ ["/rows//movies", :start_array, nil],
79
+ ["/rows//movies/", :number, 2],
80
+ ["/rows//movies/", :number, 3],
81
+ ["/rows//movies", :end_array, nil],
82
+ ["/rows/", :end_hash, nil],
83
+ ["/rows", :end_array, nil],
84
+ ["", :end_hash, nil]
85
+ ]
86
+ assert_equal expected, events
87
+ end
88
+
89
+ def test_it_yields_enumerator
90
+ parser = YAJI::Parser.new('{"hello":"world"}')
91
+ e = parser.parse
92
+ assert_equal ["", :start_hash, nil], e.next
93
+ assert_equal ["", :hash_key, "hello"], e.next
94
+ assert_equal ["/hello", :string, "world"], e.next
95
+ assert_equal ["", :end_hash, nil], e.next
96
+ assert_raises(StopIteration) { e.next }
97
+ end
98
+
99
+ def test_it_symbolizes_keys
100
+ parser = YAJI::Parser.new('{"hello":"world"}', :symbolize_keys => true)
101
+ e = parser.parse
102
+ expected = [
103
+ ["", :start_hash, nil],
104
+ ["", :hash_key, :hello],
105
+ ["/hello", :string, "world"],
106
+ ["", :end_hash, nil]
107
+ ]
108
+ assert_equal expected, e.to_a
109
+ end
110
+
111
+ def test_it_build_ruby_objects
112
+ parser = YAJI::Parser.new(toys_json_str)
113
+ objects = []
114
+ parser.each do |o|
115
+ objects << o
116
+ end
117
+ expected = [{"total_rows" => 2,
118
+ "rows" => [
119
+ {
120
+ "id" => "buzz",
121
+ "props" => { "humanoid"=> true, "armed"=> true },
122
+ "movies" => [1,2,3]
123
+ },
124
+ {
125
+ "id" => "barbie",
126
+ "props" => { "humanoid"=> true, "armed"=> false },
127
+ "movies" => [2,3]
128
+ }
129
+ ]}]
130
+ assert_equal expected, objects
131
+ end
132
+
133
+ def test_it_yields_whole_array
134
+ parser = YAJI::Parser.new(toys_json_str)
135
+ objects = []
136
+ parser.each("/rows") do |o|
137
+ objects << o
138
+ end
139
+ expected = [[{
140
+ "id" => "buzz",
141
+ "props" => { "humanoid"=> true, "armed"=> true },
142
+ "movies" => [1,2,3]
143
+ },
144
+ {
145
+ "id" => "barbie",
146
+ "props" => { "humanoid"=> true, "armed"=> false },
147
+ "movies" => [2,3]
148
+ }]]
149
+ assert_equal expected, objects
150
+ end
151
+
152
+ def test_it_yeilds_array_contents_row_by_row
153
+ parser = YAJI::Parser.new(toys_json_str)
154
+ objects = []
155
+ parser.each("/rows/") do |o|
156
+ objects << o
157
+ end
158
+ expected = [{
159
+ "id" => "buzz",
160
+ "props" => { "humanoid"=> true, "armed"=> true },
161
+ "movies" => [1,2,3]
162
+ },
163
+ {
164
+ "id" => "barbie",
165
+ "props" => { "humanoid"=> true, "armed"=> false },
166
+ "movies" => [2,3]
167
+ }]
168
+ assert_equal expected, objects
169
+ end
170
+
171
+ def test_it_could_curb_async_approach
172
+ curl = Curl::Easy.new('http://avsej.net/test.json')
173
+ parser = YAJI::Parser.new(curl)
174
+ object = parser.each.to_a.first
175
+ expected = {"foo"=>"bar", "baz"=>{"nums"=>[42, 3.1415]}}
176
+ assert_equal expected, object
177
+ end
178
+
179
+ def test_it_allow_several_selectors
180
+ parser = YAJI::Parser.new(toys_json_str)
181
+ objects = []
182
+ parser.each(["/total_rows", "/rows/"]) do |o|
183
+ objects << o
184
+ end
185
+ expected = [2,
186
+ {
187
+ "id" => "buzz",
188
+ "props" => { "humanoid"=> true, "armed"=> true },
189
+ "movies" => [1,2,3]
190
+ },
191
+ {
192
+ "id" => "barbie",
193
+ "props" => { "humanoid"=> true, "armed"=> false },
194
+ "movies" => [2,3]
195
+ }]
196
+ assert_equal expected, objects
197
+ end
198
+
199
+ def test_it_optionally_yields_object_path
200
+ parser = YAJI::Parser.new(toys_json_str)
201
+ objects = []
202
+ parser.each(["/total_rows", "/rows/"], :with_path => true) do |o|
203
+ objects << o
204
+ end
205
+ expected = [["/total_rows", 2],
206
+ ["/rows/", {
207
+ "id" => "buzz",
208
+ "props" => { "humanoid"=> true, "armed"=> true },
209
+ "movies" => [1,2,3]
210
+ }],
211
+ ["/rows/", {
212
+ "id" => "barbie",
213
+ "props" => { "humanoid"=> true, "armed"=> false },
214
+ "movies" => [2,3]
215
+ }]]
216
+ assert_equal expected, objects
217
+ end
218
+
219
+ def test_it_allows_to_specify_filter_and_options_at_initialization
220
+ parser = YAJI::Parser.new(toys_json_str,
221
+ :filter => ["/total_rows", "/rows/"],
222
+ :with_path => true)
223
+ objects = []
224
+ parser.each do |o|
225
+ objects << o
226
+ end
227
+ expected = [["/total_rows", 2],
228
+ ["/rows/", {
229
+ "id" => "buzz",
230
+ "props" => { "humanoid"=> true, "armed"=> true },
231
+ "movies" => [1,2,3]
232
+ }],
233
+ ["/rows/", {
234
+ "id" => "barbie",
235
+ "props" => { "humanoid"=> true, "armed"=> false },
236
+ "movies" => [2,3]
237
+ }]]
238
+ assert_equal expected, objects
239
+ end
240
+
241
+ def test_it_doesnt_raise_exception_on_empty_input
242
+ YAJI::Parser.new("").parse
243
+ YAJI::Parser.new(" ").parse
244
+ YAJI::Parser.new("\n").parse
245
+ YAJI::Parser.new(" \n\n ").parse
246
+ end
247
+
248
+ def test_it_allows_to_create_parser_without_input
249
+ YAJI::Parser.new
250
+ YAJI::Parser.new(:filter => 'test')
251
+ YAJI::Parser.new(:with_path => true)
252
+ end
253
+
254
+ def test_it_raises_argument_error_for_parser_without_input
255
+ parser = YAJI::Parser.new
256
+ assert_raises(ArgumentError) do
257
+ parser.parse
258
+ end
259
+ assert_raises(ArgumentError) do
260
+ parser.each{|x| }
261
+ end
262
+ end
263
+
264
+ def test_it_raises_argument_error_on_write_without_callback_set_up
265
+ parser = YAJI::Parser.new
266
+ assert_raises(ArgumentError) do
267
+ parser.write('{"hello":"world"}')
268
+ end
269
+ end
270
+
271
+ def test_it_allows_to_feed_the_data_on_the_fly
272
+ parser = YAJI::Parser.new(:filter => '/rows/')
273
+
274
+ objects = []
275
+ parser.on_object do |obj|
276
+ objects << obj
277
+ end
278
+
279
+ parser.write(<<-JSON)
280
+ {
281
+ "total_rows": 2,
282
+ "rows": [
283
+ {
284
+ JSON
285
+ parser.write(<<-JSON)
286
+ "id": "buzz",
287
+ "props": {
288
+ "humanoid": true,
289
+ "armed": true
290
+ },
291
+ "movies": [1,2,3]
292
+ },
293
+ JSON
294
+ data = <<-JSON
295
+ {
296
+ "id": "barbie",
297
+ "props": {
298
+ "humanoid": true,
299
+ "armed": false
300
+ },
301
+ "movies": [2,3]
302
+ }
303
+ ]
304
+ }
305
+ JSON
306
+ parser << data
307
+
308
+ expected = [{
309
+ "id" => "buzz",
310
+ "props" => { "humanoid"=> true, "armed"=> true },
311
+ "movies" => [1,2,3]
312
+ },
313
+ {
314
+ "id" => "barbie",
315
+ "props" => { "humanoid"=> true, "armed"=> false },
316
+ "movies" => [2,3]
317
+ }]
318
+ assert_equal expected, objects
319
+ end
320
+
321
+ def test_it_parses_chunked_data
322
+ generator = Generator.new(['{"total_rows":', '0,"offset":0,"rows":[]', '}'])
323
+ iter = YAJI::Parser.new(generator).each(["total_rows", "/rows/", "/errors/"], :with_path => true)
324
+ begin
325
+ loop do
326
+ iter.next
327
+ end
328
+ rescue StopIteration
329
+ end
330
+ end
331
+
332
+ def test_it_skips_empty_chunks
333
+ generator = Generator.new(['{"total_rows":', '0,"offset":0,"rows":[]', '}', '', nil])
334
+ iter = YAJI::Parser.new(generator).each(["total_rows", "/rows/", "/errors/"], :with_path => true)
335
+ begin
336
+ loop do
337
+ iter.next
338
+ end
339
+ rescue StopIteration
340
+ end
341
+ end
342
+
343
+ protected
344
+
345
+ def toys_json_str
346
+ <<-JSON
347
+ {
348
+ "total_rows": 2,
349
+ "rows": [
350
+ {
351
+ "id": "buzz",
352
+ "props": {
353
+ "humanoid": true,
354
+ "armed": true
355
+ },
356
+ "movies": [1,2,3]
357
+ },
358
+ {
359
+ "id": "barbie",
360
+ "props": {
361
+ "humanoid": true,
362
+ "armed": false
363
+ },
364
+ "movies": [2,3]
365
+ }
366
+ ]
367
+ }
368
+ JSON
369
+ end
370
+ end