From 95ac4b066615d044ec94e6f6b411eec9fe0d0fad Mon Sep 17 00:00:00 2001 From: Gustav Munkby Date: Mon, 23 May 2016 13:34:56 +0200 Subject: [PATCH] Restore support for legacy unquoted string literals While we definitely want to transition away from unquoted string literals, it seems reasonable to do that over time, similarly to how it was handled in jmespath.py. The reason for doing so, is to allow for a simple upgrade path, where a new version of jmespath.rb can be installed, and the software using it can transition all its configuration to use the new format, and then the jmespath.rb version could be upgraded to not even support these expressions. The tests were copied verbatim from jmespath.py, and are not included in the compliance test suite, so comes with an explicit license, which the compliance test suite does not. JSON doesn't allow for comments, so I'm not sure how to handle the attribution clause of the jmespath.py license --- lib/jmespath/lexer.rb | 10 ++++--- spec/compliance_spec.rb | 2 +- spec/legacy/literal.json | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 spec/legacy/literal.json diff --git a/lib/jmespath/lexer.rb b/lib/jmespath/lexer.rb index 43dddfe..2ba7346 100644 --- a/lib/jmespath/lexer.rb +++ b/lib/jmespath/lexer.rb @@ -243,7 +243,7 @@ def tokenize(expression) token = inside(chars, '"', T_QUOTED_IDENTIFIER) if token.type == T_QUOTED_IDENTIFIER token.value = "\"#{token.value}\"" - token = parse_json(token) + token = parse_json(token, true) end tokens << token when STATE_EQ @@ -295,9 +295,13 @@ def inside(chars, delim, type) Token.new(type, buffer.join, position) end - def parse_json(token) + def parse_json(token, quoted=false) begin - token.value = JSON.load(token.value) + if quoted + token.value = JSON.load(token.value) + else + token.value = JSON.load(token.value) rescue JSON.load(sprintf('"%s"', token.value.lstrip)) + end rescue JSON::ParserError token.type = T_UNKNOWN end diff --git a/spec/compliance_spec.rb b/spec/compliance_spec.rb index 41057e9..c906701 100644 --- a/spec/compliance_spec.rb +++ b/spec/compliance_spec.rb @@ -5,7 +5,7 @@ SimpleCov.command_name('test:compliance') describe 'Compliance' do - Dir.glob('spec/compliance/*.json').each do |path| + Dir.glob('spec/{compliance,legacy}/*.json').each do |path| test_file = File.basename(path).split('.').first next if test_file == 'benchmarks' diff --git a/spec/legacy/literal.json b/spec/legacy/literal.json new file mode 100644 index 0000000..a9e5355 --- /dev/null +++ b/spec/legacy/literal.json @@ -0,0 +1,56 @@ +[ + { + "given": { + "foo": [{"name": "a"}, {"name": "b"}], + "bar": {"baz": "qux"} + }, + "cases": [ + { + "expression": "`foo`", + "result": "foo" + }, + { + "comment": "Double quotes must be escaped.", + "expression": "`foo\\\"quote`", + "result": "foo\"quote" + }, + { + "expression": "`✓`", + "result": "✓" + }, + { + "comment": "Double quote in literal", + "expression": "`foo\\\"bar`", + "result": "foo\"bar" + }, + { + "expression": "`1\\``", + "result": "1`" + }, + { + "comment": "Multiple literal expressions with escapes", + "expression": "`\\\\`.{a:`b`}", + "result": {"a": "b"} + } + ] + }, + { + "comment": "Literals", + "given": {"type": "object"}, + "cases": [ + { + "expression": "`foo`", + "result": "foo" + }, + { + "expression": "` foo`", + "result": "foo" + }, + { + "comment": "Literal on RHS of subexpr not allowed", + "expression": "foo.`bar`", + "error": "syntax" + } + ] + } +] \ No newline at end of file