ffi-yajl 2.0.0 → 2.1.0

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: 22f963e220dde27e277e387e7dfba256859da2c8
4
- data.tar.gz: d52391f8a6449ce89cbe3bb39a03cec421769967
3
+ metadata.gz: 948084f681256d2d301e01415ce82e335f1bee52
4
+ data.tar.gz: f749ab5a3e388d3c069825b00cd37c30796db6d9
5
5
  SHA512:
6
- metadata.gz: bf8965e64e5122273aea126fa4e6d284537e9680d298b4c6a24ff6a0c41f5540a2b22d6fb7181a6df80455909c05e943b55437aec7b54f041f5e99784b821970
7
- data.tar.gz: 094122dadd975df2181a4fc51a6462086e37d6800ed05888f9b3c6591493ea3171c02d0b1bc1bd14122af4ec193bd569aafbd8b5dca4b136b17605f9c7a1a1e9
6
+ metadata.gz: fda05bb34154de35d5b9f2a9d3f3625267a2dd35ad3e048243a8cbf904397ae001462bbeb449e2d83d00564291a47152dff4414d36a217d7fdaf0bef5a288543
7
+ data.tar.gz: 9c47d061b3055164397a98666cf34786ff0341c0ccccb9fdb95655927150af3adbedc9d6ffcace61883cfb3f39e45102ee3fc990891cc5b4769de86f044a7f93
data/README.md CHANGED
@@ -36,16 +36,30 @@ could support non-MRI rubies) and we also needed some bug fixes in
36
36
  yajl2, but the maintainer wasn't able to devote enough time to the
37
37
  project to make these updates in a timeframe that worked for us.
38
38
 
39
+ ## Yajl Library Packaging
40
+
41
+ This library prefers to use the embedded yajl 2.x C library packaged in the
42
+ libyajl2 gem. In order to use the operating system yajl library (which must be
43
+ yajl 2.x) the environment variable `USE_SYSTEM_LIBYAJL2` can be set before
44
+ installing or bundling libyajl2. This will force the libyajl2 gem to skip
45
+ compiling its embedded library and the ffi-yajl gem will fallback to using the
46
+ system yajl library.
47
+
39
48
  ## Thanks
40
49
 
41
- This was initially going to be a clean rewrite of an ffi ruby wrapper around yajl2, but as it progressed more and more code was
42
- pulled in from brianmario's existing yajl-ruby gem, particularly all the c extension code, lots of specs and the benchmarks. And the
43
- process of writing this would have been much more difficult without being able to draw heavily from already solved problems in
50
+ This was initially going to be a clean rewrite of an ffi ruby wrapper around
51
+ yajl2, but as it progressed more and more code was pulled in from brianmario's
52
+ existing yajl-ruby gem, particularly all the c extension code, lots of specs
53
+ and the benchmarks. And the process of writing this would have been much more
54
+ difficult without being able to draw heavily from already solved problems in
44
55
  yajl-ruby.
45
56
 
46
57
  ## License
47
58
 
48
- Given that this draws heavily from the yajl-ruby sources, and could be considered a derivative work, the MIT License from that
49
- project has been preserved and this source code has deliberately not been dual licensed under Chef's typical Apache License.
50
- See the [LICENSE](https://github.com/chef/ffi-yajl/blob/master/LICENSE) file in this project.
59
+ Given that this draws heavily from the yajl-ruby sources, and could be
60
+ considered a derivative work, the MIT License from that project has been
61
+ preserved and this source code has deliberately not been dual licensed under
62
+ Chef's typical Apache License. See the
63
+ [LICENSE](https://github.com/chef/ffi-yajl/blob/master/LICENSE) file in this
64
+ project.
51
65
 
data/Rakefile CHANGED
@@ -51,6 +51,13 @@ Rake::ExtensionTask.new do |ext|
51
51
  ext.gem_spec = spec
52
52
  end
53
53
 
54
+ Rake::ExtensionTask.new do |ext|
55
+ ext.name = 'dlopen'
56
+ ext.lib_dir = 'lib/ffi_yajl/ext'
57
+ ext.ext_dir = 'ext/ffi_yajl/ext/dlopen'
58
+ ext.gem_spec = spec
59
+ end
60
+
54
61
  #
55
62
  # test tasks
56
63
  #
@@ -0,0 +1,40 @@
1
+ #include <ruby.h>
2
+
3
+ #if defined(HAVE_DLFCN_H)
4
+ # include <dlfcn.h>
5
+ #ifndef RTLD_LAZY
6
+ #define RTLD_LAZY 0
7
+ #endif
8
+ #ifndef RTLD_GLOBAL
9
+ #define RTLD_GLOBAL 0
10
+ #endif
11
+ #ifndef RTLD_NOW
12
+ #define RTLD_NOW 0
13
+ #endif
14
+ #else
15
+ # if defined(_WIN32)
16
+ # include <windows.h>
17
+ # define dlopen(name,flag) ((void*)LoadLibrary(name))
18
+ # define dlerror() strerror(rb_w32_map_errno(GetLastError()))
19
+ # define dlsym(handle,name) ((void*)GetProcAddress((handle),(name)))
20
+ # define RTLD_LAZY -1
21
+ # define RTLD_NOW -1
22
+ # define RTLD_GLOBAL -1
23
+ # endif
24
+ #endif
25
+
26
+ static VALUE mFFI_Yajl, mDlopen, mExt;
27
+
28
+ static VALUE mDlopen_dlopen(VALUE self, VALUE file) {
29
+ if (dlopen(RSTRING_PTR(file), RTLD_NOW|RTLD_GLOBAL) == NULL) {
30
+ rb_raise(rb_eArgError, "%s", dlerror());
31
+ }
32
+ return Qnil;
33
+ }
34
+
35
+ void Init_dlopen() {
36
+ mFFI_Yajl = rb_define_module("FFI_Yajl");
37
+ mExt = rb_define_module_under(mFFI_Yajl, "Ext");
38
+ mDlopen = rb_define_module_under(mExt, "Dlopen");
39
+ rb_define_method(mDlopen, "dlopen", mDlopen_dlopen, 1);
40
+ }
@@ -0,0 +1,15 @@
1
+ require 'mkmf'
2
+ require 'rubygems'
3
+
4
+ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
5
+
6
+ puts $CFLAGS
7
+ puts $LDFLAGS
8
+
9
+ have_header("dlfcn.h")
10
+
11
+ have_library("dl", "dlopen")
12
+
13
+ dir_config 'dlopen'
14
+
15
+ create_makefile 'ffi_yajl/ext/dlopen'
@@ -2,7 +2,7 @@
2
2
  #include <yajl/yajl_gen.h>
3
3
 
4
4
  static VALUE mFFI_Yajl, mExt, mEncoder, mEncoder2, cEncodeError;
5
- static VALUE cDate, cTime, cDateTime;
5
+ static VALUE cDate, cTime, cDateTime, cStringIO;
6
6
  static VALUE cYajl_Gen;
7
7
 
8
8
  /* FIXME: the json gem does a whole bunch of indirection around monkeypatching... not sure if we need to as well... */
@@ -295,11 +295,8 @@ static VALUE rb_cString_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
295
295
  return Qnil;
296
296
  }
297
297
 
298
- /* calls #to_s on an object to encode it */
299
- static VALUE object_to_s_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
298
+ static VALUE string_ffi_yajl(VALUE str, VALUE rb_yajl_gen, VALUE state) {
300
299
  yajl_gen_status status;
301
- ID sym_to_s = rb_intern("to_s");
302
- VALUE str = rb_funcall(self, sym_to_s, 0);
303
300
  char *cptr = RSTRING_PTR(str);
304
301
  int len = RSTRING_LEN(str);
305
302
  struct yajl_gen_t *yajl_gen;
@@ -312,6 +309,13 @@ static VALUE object_to_s_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
312
309
  return Qnil;
313
310
  }
314
311
 
312
+ /* calls #to_s on an object to encode it */
313
+ static VALUE object_to_s_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
314
+ ID sym_to_s = rb_intern("to_s");
315
+ VALUE str = rb_funcall(self, sym_to_s, 0);
316
+ return string_ffi_yajl(str, rb_yajl_gen, state);
317
+ }
318
+
315
319
  static VALUE rb_cSymbol_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
316
320
  return object_to_s_ffi_yajl(self, rb_yajl_gen, state);
317
321
  }
@@ -321,19 +325,15 @@ static VALUE rb_cDate_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
321
325
  }
322
326
 
323
327
  static VALUE rb_cTime_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
324
- yajl_gen_status status;
325
328
  ID sym_strftime = rb_intern("strftime");
326
329
  VALUE str = rb_funcall(self, sym_strftime, 1, rb_str_new2("%Y-%m-%d %H:%M:%S %z"));
327
- char *cptr = RSTRING_PTR(str);
328
- int len = RSTRING_LEN(str);
329
- struct yajl_gen_t *yajl_gen;
330
- Data_Get_Struct(rb_yajl_gen, struct yajl_gen_t, yajl_gen);
331
-
332
- CHECK_STATUS(
333
- yajl_gen_string(yajl_gen, (unsigned char *)cptr, len)
334
- );
330
+ return string_ffi_yajl(str, rb_yajl_gen, state);
331
+ }
335
332
 
336
- return Qnil;
333
+ static VALUE rb_cStringIO_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
334
+ ID sym_read = rb_intern("read");
335
+ VALUE str = rb_funcall(self, sym_read, 0);
336
+ return string_ffi_yajl(str, rb_yajl_gen, state);
337
337
  }
338
338
 
339
339
  static VALUE rb_cDateTime_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) {
@@ -373,6 +373,7 @@ void Init_encoder() {
373
373
  cDate = rb_define_class("Date", rb_cObject);
374
374
  cTime = rb_define_class("Time", rb_cObject);
375
375
  cDateTime = rb_define_class("DateTime", cDate);
376
+ cStringIO = rb_define_class("StringIO", rb_cData);
376
377
 
377
378
  rb_define_method(rb_cHash, "ffi_yajl", rb_cHash_ffi_yajl, 2);
378
379
  rb_define_method(rb_cArray, "ffi_yajl", rb_cArray_ffi_yajl, 2);
@@ -387,5 +388,6 @@ void Init_encoder() {
387
388
  rb_define_method(cDate, "ffi_yajl", rb_cDate_ffi_yajl, 2);
388
389
  rb_define_method(cTime, "ffi_yajl", rb_cTime_ffi_yajl, 2);
389
390
  rb_define_method(cDateTime, "ffi_yajl", rb_cDateTime_ffi_yajl, 2);
391
+ rb_define_method(cStringIO, "ffi_yajl", rb_cStringIO_ffi_yajl, 2);
390
392
  rb_define_method(rb_cObject, "ffi_yajl", rb_cObject_ffi_yajl, 2);
391
393
  }
@@ -11,6 +11,7 @@ static VALUE mFFI_Yajl, mExt, mParser, cParseError;
11
11
  typedef struct {
12
12
  VALUE self;
13
13
  int symbolizeKeys;
14
+ int uniqueKeyChecking;
14
15
  } CTX;
15
16
 
16
17
  void set_value(CTX *ctx, VALUE val) {
@@ -23,6 +24,12 @@ void set_value(CTX *ctx, VALUE val) {
23
24
  rb_ary_push(last, val);
24
25
  break;
25
26
  case T_HASH:
27
+ if ( ctx->uniqueKeyChecking ) {
28
+ ID sym_has_key = rb_intern("has_key?");
29
+ if ( rb_funcall(last, sym_has_key, 1, key) == Qtrue ) {
30
+ rb_raise(cParseError, "repeated key: %s", RSTRING_PTR(key));
31
+ }
32
+ }
26
33
  rb_hash_aset(last, key, val);
27
34
  break;
28
35
  default:
@@ -163,7 +170,7 @@ static yajl_callbacks callbacks = {
163
170
  end_array_callback,
164
171
  };
165
172
 
166
- int get_opts_key(VALUE self, char *key) {
173
+ int get_opts_key(VALUE self, const char *key) {
167
174
  VALUE opts = rb_iv_get(self, "@opts");
168
175
  if (TYPE(opts) != T_HASH) {
169
176
  rb_raise(rb_eTypeError, "opts is not a valid hash");
@@ -182,6 +189,7 @@ static VALUE mParser_do_yajl_parse(VALUE self, VALUE str, VALUE yajl_opts) {
182
189
 
183
190
  ctx.self = self;
184
191
  ctx.symbolizeKeys = get_opts_key(self, "symbolize_keys");
192
+ ctx.uniqueKeyChecking = get_opts_key(self, "unique_key_checking");
185
193
 
186
194
  hand = yajl_alloc(&callbacks, NULL, (void *)&ctx);
187
195
 
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  require 'ffi_yajl/benchmark/encode.rb'
3
24
  require 'ffi_yajl/benchmark/encode_profile.rb'
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  module FFI_Yajl
3
24
  class EncodeError < StandardError; end
data/lib/ffi_yajl/ext.rb CHANGED
@@ -1,71 +1,37 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
1
23
  require 'rubygems'
2
24
 
3
25
  require 'ffi_yajl/encoder'
4
26
  require 'ffi_yajl/parser'
5
- require 'ffi'
6
- require 'libyajl2'
7
- require 'ffi_yajl/platform'
27
+ require 'ffi_yajl/ext/dlopen'
28
+ require 'ffi_yajl/map_library_name'
8
29
 
9
30
  module FFI_Yajl
10
- extend FFI_Yajl::Platform
11
-
12
- # FIXME: DRY with ffi_yajl/ffi.rb
13
- # FIXME: extract map_library_name from FFI and stop requiring it at the top level
14
- # so that the C-library can be installed without FFI
15
- libname = ::FFI.map_library_name("yajl")
16
- # awful windows patch, but there is an open issue to entirely replace FFI.map_library_name already
17
- libname = "libyajl.so" if windows?
18
- libpath = File.expand_path(File.join(Libyajl2.opt_path, libname))
19
- libpath.gsub!(/dylib/, 'bundle')
20
- libpath = ::FFI.map_library_name("yajl") unless File.exist?(libpath)
21
-
22
- #
23
- # FFS, what exactly was so wrong with DL.dlopen that ruby had to get rid of it???
24
- #
25
-
26
- def self.try_fiddle_dlopen(libpath)
27
- require 'fiddle'
28
- if defined?(Fiddle) && Fiddle.respond_to?(:dlopen)
29
- ::Fiddle.dlopen(libpath)
30
- true
31
- else
32
- false
33
- end
34
- rescue LoadError
35
- return false
36
- end
31
+ extend FFI_Yajl::MapLibraryName
32
+ extend FFI_Yajl::Ext::Dlopen
37
33
 
38
- def self.try_dl_dlopen(libpath)
39
- require 'dl'
40
- if defined?(DL) && DL.respond_to?(:dlopen)
41
- ::DL.dlopen(libpath)
42
- true
43
- else
44
- false
45
- end
46
- rescue LoadError
47
- return false
48
- end
49
-
50
- def self.try_ffi_dlopen(libpath)
51
- require 'ffi'
52
- require 'rbconfig'
53
- extend ::FFI::Library
54
- ffi_lib 'dl'
55
- attach_function 'dlopen', :dlopen, [:string, :int], :void
56
- if RbConfig::CONFIG['host_os'] =~ /linux/i
57
- dlopen libpath, 0x102 # linux: RTLD_GLOBAL | RTLD_NOW
58
- else
59
- dlopen libpath, 0
60
- end
61
- true
62
- rescue LoadError
63
- return false
64
- end
65
-
66
- unless try_fiddle_dlopen(libpath) || try_dl_dlopen(libpath) || try_ffi_dlopen(libpath)
67
- raise "cannot find dlopen via Fiddle, DL or FFI, what am I supposed to do?"
68
- end
34
+ dlopen_yajl_library
69
35
 
70
36
  class Parser
71
37
  require 'ffi_yajl/ext/parser'
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  require 'ffi_yajl/ffi'
3
24
 
@@ -206,6 +227,15 @@ class String
206
227
  end
207
228
  end
208
229
 
230
+ class StringIO
231
+ def ffi_yajl(yajl_gen, state)
232
+ str = self.read
233
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
234
+ FFI_Yajl::Encoder.raise_error_for_status(status)
235
+ end
236
+ end
237
+ end
238
+
209
239
  class Date
210
240
  def ffi_yajl(yajl_gen, state)
211
241
  str = self.to_s
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  require 'ffi_yajl/ffi'
3
24
 
@@ -9,6 +30,9 @@ module FFI_Yajl
9
30
  case stack.last
10
31
  when Hash
11
32
  raise FFI_Yajl::ParseError.new("internal error: missing key in parse") if key.nil?
33
+ if @opts[:unique_key_checking] && stack.last.has_key?(key)
34
+ raise FFI_Yajl::ParseError.new("repeated key: #{key}")
35
+ end
12
36
  stack.last[key] = val
13
37
  when Array
14
38
  stack.last.push(val)
data/lib/ffi_yajl/ffi.rb CHANGED
@@ -1,23 +1,44 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
1
23
  require 'rubygems'
2
24
 
3
25
  require 'libyajl2'
4
- require 'ffi'
26
+ begin
27
+ require 'ffi'
28
+ rescue LoadError
29
+ $stderr.puts "FATAL: to use the ffi extension instead of the compiled C extension, the ffi gem must be installed"
30
+ $stderr.puts " (it is optional, so you must include it in your bundle manually)"
31
+ exit 1
32
+ end
33
+
34
+ require 'ffi_yajl/map_library_name'
5
35
 
6
36
  module FFI_Yajl
7
37
  extend ::FFI::Library
8
38
 
9
- libname = ::FFI.map_library_name("yajl")
10
- # XXX: need to replace ::FFI.map_library_name here as well
11
- libname = "libyajl.so" if libname == "yajl.dll"
12
- libpath = File.expand_path(File.join(Libyajl2.opt_path, libname))
13
- libpath.gsub!(/dylib/, 'bundle')
14
-
15
- if File.file?(libpath)
16
- # use our vendored version of libyajl2 if we find it installed
17
- ffi_lib libpath
18
- else
19
- ffi_lib 'yajl'
20
- end
39
+ extend FFI_Yajl::MapLibraryName
40
+
41
+ ffi_open_yajl_library
21
42
 
22
43
  class YajlCallbacks < ::FFI::Struct
23
44
  layout :yajl_null, :pointer,
@@ -0,0 +1,110 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'libyajl2'
24
+
25
+ # Mixin for use in finding the right yajl library on the system. The 'caller'
26
+ # needs to also mixin either the FFI module or the DLopen module. Those are
27
+ # deliberately not mixed in to avoid loading the dlopen module in the ffi
28
+ # codepath (which fails on jruby which does not have that C extension).
29
+
30
+ module FFI_Yajl
31
+ module MapLibraryName
32
+
33
+ private
34
+
35
+ # Stub for tests to override the host_os
36
+ #
37
+ # @api private
38
+ # @return Array<String> lower case ruby host_os string
39
+ def host_os
40
+ RbConfig::CONFIG['host_os'].downcase
41
+ end
42
+
43
+ # Array of yajl library names on the platform. Some platforms like Windows
44
+ # and Mac may have different names/extensions.
45
+ #
46
+ # @api private
47
+ # @return Array<String> Array of yajl library names for platform
48
+ def library_names
49
+ case host_os
50
+ when /mingw|mswin/
51
+ [ "libyajl.so", "yajl.dll" ]
52
+ when /cygwin/
53
+ [ "libyajl.so", "cygyajl.dll" ]
54
+ when /darwin/
55
+ [ "libyajl.bundle", "libyajl.dylib" ]
56
+ else
57
+ [ "libyajl.so" ]
58
+ end
59
+ end
60
+
61
+ # Array of yajl library names prepended with the libyajl2 path to use to
62
+ # load those directly and bypass the system libyajl by default. Since
63
+ # these are full paths, this API checks to ensure that the file exists on
64
+ # the filesystem. May return an empty array.
65
+ #
66
+ # @api private
67
+ # @return Array<String> Array of full paths to libyajl2 gem libraries
68
+ def expanded_library_names
69
+ library_names.map do |libname|
70
+ pathname = File.expand_path(File.join(Libyajl2.opt_path, libname))
71
+ pathname if File.file?(pathname)
72
+ end.compact
73
+ end
74
+
75
+ # Iterate across the expanded library names in the libyajl2-gem and then
76
+ # attempt to load the system libraries. Uses the native dlopen extension
77
+ # that ships in this gem.
78
+ #
79
+ # @api private
80
+ def dlopen_yajl_library
81
+ found = false
82
+ ( expanded_library_names + library_names ).each do |libname|
83
+ begin
84
+ dlopen(libname)
85
+ found = true
86
+ break
87
+ rescue ArgumentError
88
+ end
89
+ end
90
+ raise "cannot find yajl library for platform" unless found
91
+ end
92
+
93
+ # Iterate across the expanded library names in the libyajl2-gem and attempt
94
+ # to load them. If they are missing just use `ffi_lib 'yajl'` to accept
95
+ # the FFI default algorithm to find the library.
96
+ #
97
+ # @api private
98
+ def ffi_open_yajl_library
99
+ found = false
100
+ expanded_library_names.each do |libname|
101
+ begin
102
+ ffi_lib libname
103
+ found = true
104
+ rescue LoadError
105
+ end
106
+ end
107
+ ffi_lib 'yajl' unless found
108
+ end
109
+ end
110
+ end
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  module FFI_Yajl
3
24
  class ParseError < StandardError; end
@@ -54,6 +75,8 @@ module FFI_Yajl
54
75
  yajl_opts[:yajl_allow_multiple_values] = @opts[:allow_multiple_values]
55
76
  yajl_opts[:yajl_allow_partial_values] = @opts[:allow_partial_values]
56
77
 
78
+ yajl_opts[:unique_key_checking] = @opts[:unique_key_checking]
79
+
57
80
  # XXX: bug-compat with ruby-yajl
58
81
  return nil if str == ""
59
82
 
@@ -1,3 +1,25 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
1
23
  module FFI_Yajl
2
24
  module Platform
3
25
  def windows?
@@ -1,3 +1,25 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
1
23
  module FFI_Yajl
2
- VERSION = "2.0.0"
24
+ VERSION = "2.1.0"
3
25
  end
data/lib/ffi_yajl.rb CHANGED
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
22
 
2
23
  #
3
24
  # Precedence:
@@ -19,10 +40,6 @@ elsif ENV['FORCE_FFI_YAJL'] == "ffi"
19
40
  require 'ffi_yajl/ffi'
20
41
  elsif RUBY_PLATFORM == "java"
21
42
  require 'ffi_yajl/ffi'
22
- elsif defined?(Yajl)
23
- warn "the ffi-yajl and yajl-ruby gems have incompatible C libyajl libs and should not be loaded in the same Ruby VM"
24
- warn "falling back to ffi which might work (or might not, no promises)"
25
- require 'ffi_yajl/ffi'
26
43
  else
27
44
  begin
28
45
  require 'ffi_yajl/ext'
@@ -1,4 +1,25 @@
1
1
  # encoding: UTF-8
2
+ # Copyright (c) 2015 Lamont Granquist
3
+ # Copyright (c) 2015 Chef Software, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2
23
 
3
24
  require 'spec_helper'
4
25
  require 'date'
@@ -110,6 +131,11 @@ describe "FFI_Yajl::Encoder" do
110
131
  expect(encoder.encode(ruby)).to eq( %q{"2001-02-03"} )
111
132
  end
112
133
 
134
+ it "can encode StringIOs" do
135
+ ruby = { "foo" => StringIO.new('THING') }
136
+ expect(encoder.encode(ruby)).to eq("{\"foo\":\"THING\"}")
137
+ end
138
+
113
139
  context "when encoding Time objects in UTC timezone" do
114
140
  before do
115
141
  @saved_tz = ENV['TZ']
@@ -0,0 +1,117 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'spec_helper'
24
+
25
+ class Test
26
+ extend FFI_Yajl::MapLibraryName
27
+ end
28
+
29
+ host_os_library_name_mapping = {
30
+ "mingw" => [ "libyajl.so", "yajl.dll" ],
31
+ "mswin" => [ "libyajl.so", "yajl.dll" ],
32
+ "cygwin" => [ "libyajl.so", "cygyajl.dll" ],
33
+ "darwin" => [ "libyajl.bundle", "libyajl.dylib" ],
34
+ "solaris2" => [ "libyajl.so" ],
35
+ "linux" => [ "libyajl.so" ],
36
+ "aix" => [ "libyajl.so" ],
37
+ "hpux" => [ "libyajl.so" ],
38
+ "netbsd" => [ "libyajl.so" ],
39
+ "openbsd" => [ "libyajl.so" ],
40
+ "freebsd" => [ "libyajl.so" ],
41
+ }
42
+
43
+ describe "FFI_Yajl::MapLibraryName" do
44
+ let(:libyajl2_opt_path) { "/libyajl2/lib" }
45
+ before do
46
+ allow(Libyajl2).to receive(:opt_path).and_return(libyajl2_opt_path)
47
+ end
48
+
49
+ host_os_library_name_mapping.each do |host_os, library_names|
50
+
51
+ context "#library_names" do
52
+ it "maps #{host_os} correctly" do
53
+ allow(Test).to receive(:host_os).and_return(host_os)
54
+ expect(Test.send(:library_names)).to eq(library_names)
55
+ end
56
+ end
57
+
58
+ context "#expanded_library_names" do
59
+ it "maps #{host_os} correctly" do
60
+ allow(Test).to receive(:host_os).and_return(host_os)
61
+ expanded_library_names = []
62
+ library_names.each do |library_name|
63
+ path = File.expand_path(File.join(libyajl2_opt_path, library_name))
64
+ expanded_library_names.push(path)
65
+ expect(File).to receive(:file?).with(path).and_return(true)
66
+ end
67
+ expect(Test.send(:expanded_library_names)).to eq(expanded_library_names)
68
+ end
69
+ end
70
+
71
+ context "#dlopen_yajl_library" do
72
+ it "should call dlopen against an expanded library name if it finds it on #{host_os}" do
73
+ allow(Test).to receive(:host_os).and_return(host_os)
74
+ library_names.each do |library_name|
75
+ path = File.expand_path(File.join(libyajl2_opt_path, library_name))
76
+ allow(File).to receive(:file?).with(path).and_return(true)
77
+ allow(Test).to receive(:dlopen).with(path).and_return(nil)
78
+ end
79
+ Test.send(:dlopen_yajl_library)
80
+ end
81
+ it "if dlopen calls all raise it should still use the short names on #{host_os}" do
82
+ allow(Test).to receive(:host_os).and_return(host_os)
83
+ library_names.each do |library_name|
84
+ path = File.expand_path(File.join(libyajl2_opt_path, library_name))
85
+ allow(File).to receive(:file?).with(path).and_return(true)
86
+ allow(Test).to receive(:dlopen).with(path).and_raise(ArgumentError)
87
+ end
88
+ allow(Test).to receive(:dlopen).with(library_names.first).and_return(nil)
89
+ Test.send(:dlopen_yajl_library)
90
+ end
91
+ end
92
+
93
+ context "ffi_open_yajl_library" do
94
+ it "should call ffi_lib against an expanded library name if it finds it on #{host_os}" do
95
+ allow(Test).to receive(:host_os).and_return(host_os)
96
+ library_names.each do |library_name|
97
+ path = File.expand_path(File.join(libyajl2_opt_path, library_name))
98
+ allow(File).to receive(:file?).with(path).and_return(true)
99
+ allow(Test).to receive(:ffi_lib).with(path).and_return(nil)
100
+ end
101
+ Test.send(:ffi_open_yajl_library)
102
+ end
103
+
104
+ it "if dlopen calls all raise it should still use 'yajl' on #{host_os}" do
105
+ allow(Test).to receive(:host_os).and_return(host_os)
106
+ library_names.each do |library_name|
107
+ path = File.expand_path(File.join(libyajl2_opt_path, library_name))
108
+ allow(File).to receive(:file?).with(path).and_return(true)
109
+ allow(Test).to receive(:ffi_lib).with(path).and_raise(LoadError)
110
+ end
111
+ allow(Test).to receive(:ffi_lib).with('yajl').and_return(nil)
112
+ Test.send(:ffi_open_yajl_library)
113
+ end
114
+ end
115
+
116
+ end
117
+ end
@@ -1,4 +1,25 @@
1
1
  # encoding: UTF-8
2
+ # Copyright (c) 2015 Lamont Granquist
3
+ # Copyright (c) 2015 Chef Software, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2
23
 
3
24
  require 'spec_helper'
4
25
 
@@ -453,7 +474,9 @@ describe "FFI_Yajl::Parser" do
453
474
  end
454
475
  end
455
476
 
456
- context "when parsing big floats", :ruby_gte_193 => true do
477
+ # NOTE: parsing floats with 8 million digits on windows has some kind of huge
478
+ # perf issues likely in ruby and/or the underlying windows libs
479
+ context "when parsing big floats", :ruby_gte_193 => true, :unix_only => true do
457
480
  let(:json) { '[0.' + '1' * 2**23 + ']' }
458
481
 
459
482
  it "parses" do
@@ -469,6 +492,21 @@ describe "FFI_Yajl::Parser" do
469
492
  expect{ parser }.not_to raise_error
470
493
  end
471
494
  end
495
+
496
+ context "should ignore repeated keys by default" do
497
+ let(:json) { '{"foo":"bar","foo":"baz"}' }
498
+ it "should replace the first hash key with the second" do
499
+ expect(parser).to eql( "foo" => "baz" )
500
+ end
501
+ end
502
+
503
+ context "should raise an exception for repeated keys" do
504
+ let(:json) { '{"foo":"bar","foo":"baz"}' }
505
+ let(:options) { { :unique_key_checking => true } }
506
+ it "should raise" do
507
+ expect{ parser }.to raise_error(FFI_Yajl::ParseError)
508
+ end
509
+ end
472
510
  end
473
511
 
474
512
  context "when options are set to empty hash" do
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,40 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
1
23
  $: << File.expand_path(File.join(File.dirname( __FILE__ ), "../lib"))
2
24
 
25
+ # load yajl-ruby into the same process (tests that both c-libs can be
26
+ # linked in the same process). this should work, see:
27
+ # http://stackoverflow.com/questions/3232822/linking-with-multiple-versions-of-a-library
28
+ begin
29
+ require 'yajl'
30
+ rescue LoadError
31
+ # yajl can't be installed on jruby
32
+ end
33
+
3
34
  require 'ffi_yajl'
4
35
 
5
36
  RSpec.configure do |c|
37
+ c.filter_run_excluding :unix_only => true unless RUBY_PLATFORM !~ /mswin|mingw|windows/
6
38
  c.filter_run_excluding :ruby_gte_19 => true unless RUBY_VERSION.to_f >= 1.9
7
39
  c.filter_run_excluding :ruby_gte_193 => true unless RUBY_VERSION.to_f >= 2.0 || RUBY_VERSION =~ /^1\.9\.3/
8
40
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-yajl
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lamont Granquist
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-17 00:00:00.000000000 Z
11
+ date: 2015-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -81,33 +81,33 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.16'
83
83
  - !ruby/object:Gem::Dependency
84
- name: ffi
84
+ name: libyajl2
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.5'
89
+ version: '1.2'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '1.5'
96
+ version: '1.2'
97
97
  - !ruby/object:Gem::Dependency
98
- name: libyajl2
98
+ name: ffi
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.2'
104
- type: :runtime
103
+ version: '1.5'
104
+ type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1.2'
110
+ version: '1.5'
111
111
  description: Ruby FFI wrapper around YAJL 2.x
112
112
  email: lamont@getchef.com
113
113
  executables:
@@ -115,6 +115,7 @@ executables:
115
115
  extensions:
116
116
  - ext/ffi_yajl/ext/encoder/extconf.rb
117
117
  - ext/ffi_yajl/ext/parser/extconf.rb
118
+ - ext/ffi_yajl/ext/dlopen/extconf.rb
118
119
  extra_rdoc_files:
119
120
  - README.md
120
121
  - LICENSE
@@ -123,6 +124,8 @@ files:
123
124
  - README.md
124
125
  - Rakefile
125
126
  - bin/ffi-yajl-bench
127
+ - ext/ffi_yajl/ext/dlopen/dlopen.c
128
+ - ext/ffi_yajl/ext/dlopen/extconf.rb
126
129
  - ext/ffi_yajl/ext/encoder/encoder.c
127
130
  - ext/ffi_yajl/ext/encoder/extconf.rb
128
131
  - ext/ffi_yajl/ext/parser/extconf.rb
@@ -154,10 +157,12 @@ files:
154
157
  - lib/ffi_yajl/ffi.rb
155
158
  - lib/ffi_yajl/ffi/encoder.rb
156
159
  - lib/ffi_yajl/ffi/parser.rb
160
+ - lib/ffi_yajl/map_library_name.rb
157
161
  - lib/ffi_yajl/parser.rb
158
162
  - lib/ffi_yajl/platform.rb
159
163
  - lib/ffi_yajl/version.rb
160
164
  - spec/ffi_yajl/encoder_spec.rb
165
+ - spec/ffi_yajl/map_library_name_spec.rb
161
166
  - spec/ffi_yajl/parser_spec.rb
162
167
  - spec/spec_helper.rb
163
168
  homepage: http://github.com/chef/ffi-yajl
@@ -180,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
185
  version: '0'
181
186
  requirements: []
182
187
  rubyforge_project:
183
- rubygems_version: 2.4.3
188
+ rubygems_version: 2.4.6
184
189
  signing_key:
185
190
  specification_version: 4
186
191
  summary: Ruby FFI wrapper around YAJL 2.x