summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2015-04-17 18:05:45 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2015-04-17 18:05:45 -0700
commit846a93684d2d81ef102717004cd076c1b93544f7 (patch)
tree18615d57b3ae7d10f1a7ace71504226fde5d42ad
parent5f9b3bd8e896cdba674d16dff83d4c9463d752d7 (diff)
downloadffi-yajl-lcg/unique_key_checking.tar.gz
add :unique_key_checking flag to parserlcg/unique_key_checking
can be used to error out if keys are duplicated in input rather than silently replacing.
-rw-r--r--ext/ffi_yajl/ext/parser/parser.c10
-rw-r--r--ffi-yajl-universal-java.gemspec2
-rw-r--r--ffi-yajl.gemspec2
-rw-r--r--ffi-yajl.gemspec.shared1
-rw-r--r--lib/ffi_yajl/ffi/parser.rb3
-rw-r--r--lib/ffi_yajl/parser.rb2
-rw-r--r--spec/ffi_yajl/parser_spec.rb15
7 files changed, 32 insertions, 3 deletions
diff --git a/ext/ffi_yajl/ext/parser/parser.c b/ext/ffi_yajl/ext/parser/parser.c
index a2813af..e846c06 100644
--- a/ext/ffi_yajl/ext/parser/parser.c
+++ b/ext/ffi_yajl/ext/parser/parser.c
@@ -11,6 +11,7 @@ static VALUE mFFI_Yajl, mExt, mParser, cParseError;
typedef struct {
VALUE self;
int symbolizeKeys;
+ int uniqueKeyChecking;
} CTX;
void set_value(CTX *ctx, VALUE val) {
@@ -23,6 +24,12 @@ void set_value(CTX *ctx, VALUE val) {
rb_ary_push(last, val);
break;
case T_HASH:
+ if ( ((CTX *)ctx)->uniqueKeyChecking ) {
+ ID sym_has_key = rb_intern("has_key?");
+ if ( rb_funcall(last, sym_has_key, 1, key) == Qtrue ) {
+ rb_raise(cParseError, "repeated key: %s", RSTRING_PTR(key));
+ }
+ }
rb_hash_aset(last, key, val);
break;
default:
@@ -163,7 +170,7 @@ static yajl_callbacks callbacks = {
end_array_callback,
};
-int get_opts_key(VALUE self, char *key) {
+int get_opts_key(VALUE self, const char *key) {
VALUE opts = rb_iv_get(self, "@opts");
if (TYPE(opts) != T_HASH) {
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) {
ctx.self = self;
ctx.symbolizeKeys = get_opts_key(self, "symbolize_keys");
+ ctx.uniqueKeyChecking = get_opts_key(self, "unique_key_checking");
hand = yajl_alloc(&callbacks, NULL, (void *)&ctx);
diff --git a/ffi-yajl-universal-java.gemspec b/ffi-yajl-universal-java.gemspec
index e712372..4df0326 100644
--- a/ffi-yajl-universal-java.gemspec
+++ b/ffi-yajl-universal-java.gemspec
@@ -6,6 +6,6 @@ gemspec.platform = "universal-java"
# extensions so can we simplify the gemspecs now?
#gemspec.extensions = %w{ ext/libyajl2/extconf.rb }
-gemspec.add_dependency "ffi", "~> 1.5"
+gemspec.add_runtime_dependency "ffi", "~> 1.5"
gemspec
diff --git a/ffi-yajl.gemspec b/ffi-yajl.gemspec
index 2801527..03086fd 100644
--- a/ffi-yajl.gemspec
+++ b/ffi-yajl.gemspec
@@ -3,4 +3,6 @@ gemspec = eval(IO.read(File.expand_path(File.join(File.dirname(__FILE__), "ffi-y
gemspec.platform = Gem::Platform::RUBY
gemspec.extensions = %w{ ext/ffi_yajl/ext/encoder/extconf.rb ext/ffi_yajl/ext/parser/extconf.rb ext/ffi_yajl/ext/dlopen/extconf.rb }
+gemspec.add_development_dependency "ffi", "~> 1.5"
+
gemspec
diff --git a/ffi-yajl.gemspec.shared b/ffi-yajl.gemspec.shared
index 62fefa0..d40c0b7 100644
--- a/ffi-yajl.gemspec.shared
+++ b/ffi-yajl.gemspec.shared
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
s.add_development_dependency "rake-compiler", "~> 0.8.3"
# pin mime-types in order to work on ruby 1.8.7
s.add_development_dependency "mime-types", "~> 1.16"
- s.add_development_dependency "ffi", "~> 1.5"
s.add_dependency "libyajl2", "~> 1.2"
s.bindir = "bin"
diff --git a/lib/ffi_yajl/ffi/parser.rb b/lib/ffi_yajl/ffi/parser.rb
index b97b2de..8e4dc07 100644
--- a/lib/ffi_yajl/ffi/parser.rb
+++ b/lib/ffi_yajl/ffi/parser.rb
@@ -30,6 +30,9 @@ module FFI_Yajl
case stack.last
when Hash
raise FFI_Yajl::ParseError.new("internal error: missing key in parse") if key.nil?
+ if @opts[:unique_key_checking] && stack.last.has_key?(key)
+ raise FFI_Yajl::ParseError.new("repeated key: #{key}")
+ end
stack.last[key] = val
when Array
stack.last.push(val)
diff --git a/lib/ffi_yajl/parser.rb b/lib/ffi_yajl/parser.rb
index d8389d7..5b9a0c9 100644
--- a/lib/ffi_yajl/parser.rb
+++ b/lib/ffi_yajl/parser.rb
@@ -75,6 +75,8 @@ module FFI_Yajl
yajl_opts[:yajl_allow_multiple_values] = @opts[:allow_multiple_values]
yajl_opts[:yajl_allow_partial_values] = @opts[:allow_partial_values]
+ yajl_opts[:unique_key_checking] = @opts[:unique_key_checking]
+
# XXX: bug-compat with ruby-yajl
return nil if str == ""
diff --git a/spec/ffi_yajl/parser_spec.rb b/spec/ffi_yajl/parser_spec.rb
index 7592f67..ed6ef2a 100644
--- a/spec/ffi_yajl/parser_spec.rb
+++ b/spec/ffi_yajl/parser_spec.rb
@@ -492,6 +492,21 @@ describe "FFI_Yajl::Parser" do
expect{ parser }.not_to raise_error
end
end
+
+ context "should ignore repeated keys by default" do
+ let(:json) { '{"foo":"bar","foo":"baz"}' }
+ it "should replace the first hash key with the second" do
+ expect(parser).to eql( "foo" => "baz" )
+ end
+ end
+
+ context "should raise an exception for repeated keys" do
+ let(:json) { '{"foo":"bar","foo":"baz"}' }
+ let(:options) { { :unique_key_checking => true } }
+ it "should raise" do
+ expect{ parser }.to raise_error(FFI_Yajl::ParseError)
+ end
+ end
end
context "when options are set to empty hash" do