From 9e861c736ef88ee99cdd5910f59c9e6c5d5e607a Mon Sep 17 00:00:00 2001 From: Geophilus Durairaj Date: Tue, 24 May 2022 04:20:55 +0530 Subject: [PATCH] Revert "Add frozen_string_literal to all files and some static code cleanup" This reverts commit 62dd7b3cccd554fd68a2cd64d218f4a27928cab4. --- Gemfile | 4 +- Rakefile | 4 +- bin/jmespath.rb | 5 +- gemfiles/json-latest.gemfile | 4 +- gemfiles/json-old.gemfile | 4 +- gemfiles/json-pure.gemfile | 4 +- gemfiles/no-deps.gemfile | 4 +- jmespath.gemspec | 4 +- lib/jmespath.rb | 17 +- lib/jmespath/caching_parser.rb | 4 +- lib/jmespath/errors.rb | 4 +- lib/jmespath/lexer.rb | 242 ++++++++++++------------ lib/jmespath/nodes.rb | 14 +- lib/jmespath/nodes/and.rb | 4 +- lib/jmespath/nodes/comparator.rb | 48 +++-- lib/jmespath/nodes/condition.rb | 4 +- lib/jmespath/nodes/current.rb | 2 - lib/jmespath/nodes/expression.rb | 5 +- lib/jmespath/nodes/field.rb | 11 +- lib/jmespath/nodes/flatten.rb | 4 +- lib/jmespath/nodes/function.rb | 176 +++++++++-------- lib/jmespath/nodes/index.rb | 2 - lib/jmespath/nodes/literal.rb | 4 +- lib/jmespath/nodes/multi_select_hash.rb | 2 - lib/jmespath/nodes/multi_select_list.rb | 2 - lib/jmespath/nodes/not.rb | 4 +- lib/jmespath/nodes/or.rb | 2 - lib/jmespath/nodes/pipe.rb | 2 - lib/jmespath/nodes/projection.rb | 16 +- lib/jmespath/nodes/slice.rb | 57 +++--- lib/jmespath/nodes/subexpression.rb | 2 - lib/jmespath/parser.rb | 106 ++++++----- lib/jmespath/runtime.rb | 4 +- lib/jmespath/token.rb | 52 ++--- lib/jmespath/token_stream.rb | 9 +- lib/jmespath/util.rb | 11 +- lib/jmespath/version.rb | 4 +- spec/compliance_spec.rb | 25 +-- spec/compliance_without_errors_spec.rb | 21 +- spec/implicit_conversion_spec.rb | 30 +-- spec/indifferent_access_spec.rb | 6 +- spec/jmespath_spec.rb | 9 +- spec/spec_helper.rb | 2 - tasks/benchmark.rake | 11 +- tasks/test.rake | 6 +- 45 files changed, 475 insertions(+), 482 deletions(-) diff --git a/Gemfile b/Gemfile index bd24303..53ce4e6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,14 +1,12 @@ -# frozen_string_literal: true - source 'https://rubygems.org' gem 'rake', require: false gem 'rspec', '~> 3.0' group :docs do - gem 'rdiscount', require: false gem 'yard' gem 'yard-sitemap', '~> 1.0' + gem 'rdiscount', require: false end group :release do diff --git a/Rakefile b/Rakefile index f825d80..2ed38f2 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,6 @@ -# frozen_string_literal: true - $GEM_ROOT = File.dirname(__FILE__) -$LOAD_PATH << File.join($GEM_ROOT, 'lib') +$: << File.join($GEM_ROOT, 'lib') $VERSION = ENV['VERSION'] || File.read(File.join($GEM_ROOT, 'VERSION')) $GITHUB_ACCESS_TOKEN = ENV['JMESPATH_GITHUB_ACCESS_TOKEN'] diff --git a/bin/jmespath.rb b/bin/jmespath.rb index 999c942..0d5ecee 100755 --- a/bin/jmespath.rb +++ b/bin/jmespath.rb @@ -1,12 +1,11 @@ #!/usr/bin/env ruby -# frozen_string_literal: true -$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) +$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) require 'jmespath' require 'json' expression = ARGV[0] -json = JSON.parse($stdin.read) +json = JSON.parse(STDIN.read) $stdout.puts(JSON.dump(JMESPath.search(expression, json))) diff --git a/gemfiles/json-latest.gemfile b/gemfiles/json-latest.gemfile index 4a0f036..fb8e2a5 100644 --- a/gemfiles/json-latest.gemfile +++ b/gemfiles/json-latest.gemfile @@ -1,5 +1,3 @@ -# frozen_string_literal: true - -eval_gemfile(File.expand_path('../Gemfile', __dir__)) +eval_gemfile(File.expand_path('../../Gemfile', __FILE__)) gem 'json' diff --git a/gemfiles/json-old.gemfile b/gemfiles/json-old.gemfile index f9db5c5..35d6acc 100644 --- a/gemfiles/json-old.gemfile +++ b/gemfiles/json-old.gemfile @@ -1,5 +1,3 @@ -# frozen_string_literal: true - -eval_gemfile(File.expand_path('../Gemfile', __dir__)) +eval_gemfile(File.expand_path('../../Gemfile', __FILE__)) gem 'json', '< 2.0' diff --git a/gemfiles/json-pure.gemfile b/gemfiles/json-pure.gemfile index d9de439..6b02009 100644 --- a/gemfiles/json-pure.gemfile +++ b/gemfiles/json-pure.gemfile @@ -1,5 +1,3 @@ -# frozen_string_literal: true - -eval_gemfile(File.expand_path('../Gemfile', __dir__)) +eval_gemfile(File.expand_path('../../Gemfile', __FILE__)) gem 'json_pure', require: 'json/pure' diff --git a/gemfiles/no-deps.gemfile b/gemfiles/no-deps.gemfile index e5d32e4..6c06253 100644 --- a/gemfiles/no-deps.gemfile +++ b/gemfiles/no-deps.gemfile @@ -1,5 +1,3 @@ -# frozen_string_literal: true - -eval_gemfile(File.expand_path('../Gemfile', __dir__)) +eval_gemfile(File.expand_path('../../Gemfile', __FILE__)) # no dependency on `json` gem diff --git a/jmespath.gemspec b/jmespath.gemspec index 23a319d..e012a4f 100644 --- a/jmespath.gemspec +++ b/jmespath.gemspec @@ -1,8 +1,6 @@ -# frozen_string_literal: true - Gem::Specification.new do |spec| spec.name = 'jmespath' - spec.version = File.read(File.expand_path('VERSION', __dir__)).strip + spec.version = File.read(File.expand_path('../VERSION', __FILE__)).strip spec.summary = 'JMESPath - Ruby Edition' spec.description = 'Implements JMESPath for Ruby' spec.author = 'Trevor Rowe' diff --git a/lib/jmespath.rb b/lib/jmespath.rb index 60e234e..aa54a1e 100644 --- a/lib/jmespath.rb +++ b/lib/jmespath.rb @@ -1,10 +1,9 @@ -# frozen_string_literal: true - require 'json' require 'stringio' require 'pathname' module JMESPath + require 'jmespath/caching_parser' require 'jmespath/errors' require 'jmespath/lexer' @@ -17,6 +16,7 @@ module JMESPath require 'jmespath/version' class << self + # @param [String] expression A valid # [JMESPath](https://github.com/boto/jmespath) expression. # @param [Hash] data @@ -24,17 +24,18 @@ class << self # expression does not resolve inside `data`. def search(expression, data, runtime_options = {}) data = case data - when Hash, Struct then data # check for most common case first - when Pathname then load_json(data) - when IO, StringIO then JSON.parse(data.read) - else data - end + when Hash, Struct then data # check for most common case first + when Pathname then load_json(data) + when IO, StringIO then JSON.parse(data.read) + else data + end Runtime.new(runtime_options).search(expression, data) end # @api private def load_json(path) - JSON.parse(File.open(path, 'r', encoding: 'UTF-8', &:read)) + JSON.parse(File.open(path, 'r', encoding: 'UTF-8') { |f| f.read }) end + end end diff --git a/lib/jmespath/caching_parser.rb b/lib/jmespath/caching_parser.rb index a233e81..ffcc74d 100644 --- a/lib/jmespath/caching_parser.rb +++ b/lib/jmespath/caching_parser.rb @@ -1,7 +1,8 @@ -# frozen_string_literal: true +require 'thread' module JMESPath class CachingParser + def initialize(options = {}) @parser = options[:parser] || Parser.new(options) @mutex = Mutex.new @@ -24,5 +25,6 @@ def cache_expression(expression) @cache[expression] = @parser.parse(expression) end end + end end diff --git a/lib/jmespath/errors.rb b/lib/jmespath/errors.rb index a46f099..7374d7b 100644 --- a/lib/jmespath/errors.rb +++ b/lib/jmespath/errors.rb @@ -1,7 +1,6 @@ -# frozen_string_literal: true - module JMESPath module Errors + class Error < StandardError; end class RuntimeError < Error; end @@ -15,5 +14,6 @@ class InvalidValueError < Error; end class InvalidArityError < Error; end class UnknownFunctionError < Error; end + end end diff --git a/lib/jmespath/lexer.rb b/lib/jmespath/lexer.rb index dccecd7..f12097b 100644 --- a/lib/jmespath/lexer.rb +++ b/lib/jmespath/lexer.rb @@ -1,11 +1,10 @@ -# frozen_string_literal: true - require 'json' require 'set' module JMESPath # @api private class Lexer + T_DOT = :dot T_STAR = :star T_COMMA = :comma @@ -48,103 +47,103 @@ class Lexer STATE_AND = 13 TRANSLATION_TABLE = { - '<' => STATE_LT, - '>' => STATE_GT, - '=' => STATE_EQ, - '!' => STATE_NOT, - '[' => STATE_LBRACKET, - '|' => STATE_PIPE, - '&' => STATE_AND, - '`' => STATE_JSON_LITERAL, - '"' => STATE_QUOTED_STRING, - "'" => STATE_STRING_LITERAL, - '-' => STATE_NUMBER, - '0' => STATE_NUMBER, - '1' => STATE_NUMBER, - '2' => STATE_NUMBER, - '3' => STATE_NUMBER, - '4' => STATE_NUMBER, - '5' => STATE_NUMBER, - '6' => STATE_NUMBER, - '7' => STATE_NUMBER, - '8' => STATE_NUMBER, - '9' => STATE_NUMBER, - ' ' => STATE_WHITESPACE, + '<' => STATE_LT, + '>' => STATE_GT, + '=' => STATE_EQ, + '!' => STATE_NOT, + '[' => STATE_LBRACKET, + '|' => STATE_PIPE, + '&' => STATE_AND, + '`' => STATE_JSON_LITERAL, + '"' => STATE_QUOTED_STRING, + "'" => STATE_STRING_LITERAL, + '-' => STATE_NUMBER, + '0' => STATE_NUMBER, + '1' => STATE_NUMBER, + '2' => STATE_NUMBER, + '3' => STATE_NUMBER, + '4' => STATE_NUMBER, + '5' => STATE_NUMBER, + '6' => STATE_NUMBER, + '7' => STATE_NUMBER, + '8' => STATE_NUMBER, + '9' => STATE_NUMBER, + ' ' => STATE_WHITESPACE, "\t" => STATE_WHITESPACE, "\n" => STATE_WHITESPACE, "\r" => STATE_WHITESPACE, - '.' => STATE_SINGLE_CHAR, - '*' => STATE_SINGLE_CHAR, - ']' => STATE_SINGLE_CHAR, - ',' => STATE_SINGLE_CHAR, - ':' => STATE_SINGLE_CHAR, - '@' => STATE_SINGLE_CHAR, - '(' => STATE_SINGLE_CHAR, - ')' => STATE_SINGLE_CHAR, - '{' => STATE_SINGLE_CHAR, - '}' => STATE_SINGLE_CHAR, - '_' => STATE_IDENTIFIER, - 'A' => STATE_IDENTIFIER, - 'B' => STATE_IDENTIFIER, - 'C' => STATE_IDENTIFIER, - 'D' => STATE_IDENTIFIER, - 'E' => STATE_IDENTIFIER, - 'F' => STATE_IDENTIFIER, - 'G' => STATE_IDENTIFIER, - 'H' => STATE_IDENTIFIER, - 'I' => STATE_IDENTIFIER, - 'J' => STATE_IDENTIFIER, - 'K' => STATE_IDENTIFIER, - 'L' => STATE_IDENTIFIER, - 'M' => STATE_IDENTIFIER, - 'N' => STATE_IDENTIFIER, - 'O' => STATE_IDENTIFIER, - 'P' => STATE_IDENTIFIER, - 'Q' => STATE_IDENTIFIER, - 'R' => STATE_IDENTIFIER, - 'S' => STATE_IDENTIFIER, - 'T' => STATE_IDENTIFIER, - 'U' => STATE_IDENTIFIER, - 'V' => STATE_IDENTIFIER, - 'W' => STATE_IDENTIFIER, - 'X' => STATE_IDENTIFIER, - 'Y' => STATE_IDENTIFIER, - 'Z' => STATE_IDENTIFIER, - 'a' => STATE_IDENTIFIER, - 'b' => STATE_IDENTIFIER, - 'c' => STATE_IDENTIFIER, - 'd' => STATE_IDENTIFIER, - 'e' => STATE_IDENTIFIER, - 'f' => STATE_IDENTIFIER, - 'g' => STATE_IDENTIFIER, - 'h' => STATE_IDENTIFIER, - 'i' => STATE_IDENTIFIER, - 'j' => STATE_IDENTIFIER, - 'k' => STATE_IDENTIFIER, - 'l' => STATE_IDENTIFIER, - 'm' => STATE_IDENTIFIER, - 'n' => STATE_IDENTIFIER, - 'o' => STATE_IDENTIFIER, - 'p' => STATE_IDENTIFIER, - 'q' => STATE_IDENTIFIER, - 'r' => STATE_IDENTIFIER, - 's' => STATE_IDENTIFIER, - 't' => STATE_IDENTIFIER, - 'u' => STATE_IDENTIFIER, - 'v' => STATE_IDENTIFIER, - 'w' => STATE_IDENTIFIER, - 'x' => STATE_IDENTIFIER, - 'y' => STATE_IDENTIFIER, - 'z' => STATE_IDENTIFIER - }.freeze + '.' => STATE_SINGLE_CHAR, + '*' => STATE_SINGLE_CHAR, + ']' => STATE_SINGLE_CHAR, + ',' => STATE_SINGLE_CHAR, + ':' => STATE_SINGLE_CHAR, + '@' => STATE_SINGLE_CHAR, + '(' => STATE_SINGLE_CHAR, + ')' => STATE_SINGLE_CHAR, + '{' => STATE_SINGLE_CHAR, + '}' => STATE_SINGLE_CHAR, + '_' => STATE_IDENTIFIER, + 'A' => STATE_IDENTIFIER, + 'B' => STATE_IDENTIFIER, + 'C' => STATE_IDENTIFIER, + 'D' => STATE_IDENTIFIER, + 'E' => STATE_IDENTIFIER, + 'F' => STATE_IDENTIFIER, + 'G' => STATE_IDENTIFIER, + 'H' => STATE_IDENTIFIER, + 'I' => STATE_IDENTIFIER, + 'J' => STATE_IDENTIFIER, + 'K' => STATE_IDENTIFIER, + 'L' => STATE_IDENTIFIER, + 'M' => STATE_IDENTIFIER, + 'N' => STATE_IDENTIFIER, + 'O' => STATE_IDENTIFIER, + 'P' => STATE_IDENTIFIER, + 'Q' => STATE_IDENTIFIER, + 'R' => STATE_IDENTIFIER, + 'S' => STATE_IDENTIFIER, + 'T' => STATE_IDENTIFIER, + 'U' => STATE_IDENTIFIER, + 'V' => STATE_IDENTIFIER, + 'W' => STATE_IDENTIFIER, + 'X' => STATE_IDENTIFIER, + 'Y' => STATE_IDENTIFIER, + 'Z' => STATE_IDENTIFIER, + 'a' => STATE_IDENTIFIER, + 'b' => STATE_IDENTIFIER, + 'c' => STATE_IDENTIFIER, + 'd' => STATE_IDENTIFIER, + 'e' => STATE_IDENTIFIER, + 'f' => STATE_IDENTIFIER, + 'g' => STATE_IDENTIFIER, + 'h' => STATE_IDENTIFIER, + 'i' => STATE_IDENTIFIER, + 'j' => STATE_IDENTIFIER, + 'k' => STATE_IDENTIFIER, + 'l' => STATE_IDENTIFIER, + 'm' => STATE_IDENTIFIER, + 'n' => STATE_IDENTIFIER, + 'o' => STATE_IDENTIFIER, + 'p' => STATE_IDENTIFIER, + 'q' => STATE_IDENTIFIER, + 'r' => STATE_IDENTIFIER, + 's' => STATE_IDENTIFIER, + 't' => STATE_IDENTIFIER, + 'u' => STATE_IDENTIFIER, + 'v' => STATE_IDENTIFIER, + 'w' => STATE_IDENTIFIER, + 'x' => STATE_IDENTIFIER, + 'y' => STATE_IDENTIFIER, + 'z' => STATE_IDENTIFIER, + } - VALID_IDENTIFIERS = Set.new(%w[ - A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - a b c d e f g h i j k l m n o p q r s t u v w x y z - _ 0 1 2 3 4 5 6 7 8 9 - ]) + VALID_IDENTIFIERS = Set.new(%w( + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + a b c d e f g h i j k l m n o p q r s t u v w x y z + _ 0 1 2 3 4 5 6 7 8 9 + )) - NUMBERS = Set.new(%w[0 1 2 3 4 5 6 7 8 9]) + NUMBERS = Set.new(%w(0 1 2 3 4 5 6 7 8 9)) SIMPLE_TOKENS = { '.' => T_DOT, @@ -156,12 +155,13 @@ class Lexer '(' => T_LPAREN, ')' => T_RPAREN, '{' => T_LBRACE, - '}' => T_RBRACE - }.freeze + '}' => T_RBRACE, + } # @param [String] expression # @return [Array] def tokenize(expression) + tokens = [] chars = CharacterStream.new(expression.chars.to_a) @@ -185,11 +185,10 @@ def tokenize(expression) when STATE_IDENTIFIER start = chars.position buffer = [] - loop do + begin buffer << chars.current chars.next - break unless VALID_IDENTIFIERS.include?(chars.current) - end + end while VALID_IDENTIFIERS.include?(chars.current) tokens << Token.new( T_IDENTIFIER, buffer.join, @@ -202,11 +201,10 @@ def tokenize(expression) # consume "[", "[?" and "[]" position = chars.position actual = chars.next - case actual - when ']' + if actual == ']' chars.next tokens << Token.new(T_FLATTEN, '[]', position) - when '?' + elsif actual == '?' chars.next tokens << Token.new(T_FILTER, '[?', position) else @@ -231,11 +229,10 @@ def tokenize(expression) when STATE_NUMBER start = chars.position buffer = [] - loop do + begin buffer << chars.current chars.next - break unless NUMBERS.include?(chars.current) - end + end while NUMBERS.include?(chars.current) tokens << Token.new( T_NUMBER, buffer.join.to_i, @@ -256,7 +253,7 @@ def tokenize(expression) tokens << match_or(chars, '&', '&', T_AND, T_EXPREF) when STATE_NOT # consume not equals - tokens << match_or(chars, '!', '=', T_COMPARATOR, T_NOT) + tokens << match_or(chars, '!', '=', T_COMPARATOR, T_NOT); else # either '<' or '>' # consume less than and greater than @@ -291,7 +288,6 @@ def inside(chars, delim, type) # unclosed delimiter return Token.new(T_UNKNOWN, buffer.join, position) end - buffer << current current = chars.next end @@ -325,9 +321,11 @@ def inside(chars, delim, type) # if we have to wrap scalar JSON values to parse them or not. # @api private def self.requires_wrapping? - JSON.parse('false') - rescue JSON::ParserError - true + begin + JSON.parse('false') + rescue JSON::ParserError + true + end end if requires_wrapping? @@ -338,8 +336,8 @@ def parse_json(token, quoted = false) else begin token.value = JSON.parse("{\"value\":#{token.value}}")['value'] - rescue StandardError - token.value = JSON.parse(format('{"value":"%s"}', token.value.lstrip))['value'] + rescue + token.value = JSON.parse(sprintf('{"value":"%s"}', token.value.lstrip))['value'] end end rescue JSON::ParserError @@ -350,15 +348,11 @@ def parse_json(token, quoted = false) else def parse_json(token, quoted = false) begin - token.value = if quoted - JSON.parse(token.value) - else - begin - JSON.parse(token.value) - rescue StandardError - JSON.parse(format('"%s"', token.value.lstrip)) - end - end + if quoted + token.value = JSON.parse(token.value) + else + token.value = JSON.parse(token.value) rescue JSON.parse(sprintf('"%s"', token.value.lstrip)) + end rescue JSON::ParserError token.type = T_UNKNOWN end @@ -367,6 +361,7 @@ def parse_json(token, quoted = false) end class CharacterStream + def initialize(chars) @chars = chars @position = 0 @@ -381,7 +376,10 @@ def next @chars[@position] end - attr_reader :position + def position + @position + end + end end end diff --git a/lib/jmespath/nodes.rb b/lib/jmespath/nodes.rb index e277c39..e9ba80e 100644 --- a/lib/jmespath/nodes.rb +++ b/lib/jmespath/nodes.rb @@ -1,23 +1,23 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes class Node - def visit(value); end + def visit(value) + end def optimize self end - def chains_with?(_other) + def chains_with?(other) false end end - + require 'jmespath/nodes/subexpression' require 'jmespath/nodes/and' require 'jmespath/nodes/comparator' + require 'jmespath/nodes/comparator' require 'jmespath/nodes/condition' require 'jmespath/nodes/current' require 'jmespath/nodes/expression' @@ -32,6 +32,10 @@ def chains_with?(_other) require 'jmespath/nodes/or' require 'jmespath/nodes/pipe' require 'jmespath/nodes/projection' + require 'jmespath/nodes/projection' + require 'jmespath/nodes/projection' require 'jmespath/nodes/slice' + + end end diff --git a/lib/jmespath/nodes/and.rb b/lib/jmespath/nodes/and.rb index 7676e16..63c621f 100644 --- a/lib/jmespath/nodes/and.rb +++ b/lib/jmespath/nodes/and.rb @@ -1,8 +1,7 @@ -# frozen_string_literal: true - module JMESPath module Nodes class And < Node + def initialize(left, right) @left = left @right = right @@ -20,6 +19,7 @@ def visit(value) def optimize self.class.new(@left.optimize, @right.optimize) end + end end end diff --git a/lib/jmespath/nodes/comparator.rb b/lib/jmespath/nodes/comparator.rb index 3500319..1e49c44 100644 --- a/lib/jmespath/nodes/comparator.rb +++ b/lib/jmespath/nodes/comparator.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -14,15 +12,16 @@ def initialize(left, right) end def self.create(relation, left, right) - type = case relation - when '==' then Comparators::Eq - when '!=' then Comparators::Neq - when '>' then Comparators::Gt - when '>=' then Comparators::Gte - when '<' then Comparators::Lt - when '<=' then Comparators::Lte - end - + type = begin + case relation + when '==' then Comparators::Eq + when '!=' then Comparators::Neq + when '>' then Comparators::Gt + when '>=' then Comparators::Gte + when '<' then Comparators::Lt + when '<=' then Comparators::Lte + end + end type.new(left, right) end @@ -36,7 +35,7 @@ def optimize private - def check(_left_value, _right_value) + def check(left_value, right_value) nil end @@ -48,6 +47,7 @@ def comparable?(left_value, right_value) end module Comparators + class Eq < Comparator def check(left_value, right_value) Util.as_json(left_value) == Util.as_json(right_value) @@ -62,25 +62,41 @@ def check(left_value, right_value) class Gt < Comparator def check(left_value, right_value) - left_value > right_value if comparable?(left_value, right_value) + if comparable?(left_value, right_value) + left_value > right_value + else + nil + end end end class Gte < Comparator def check(left_value, right_value) - left_value >= right_value if comparable?(left_value, right_value) + if comparable?(left_value, right_value) + left_value >= right_value + else + nil + end end end class Lt < Comparator def check(left_value, right_value) - left_value < right_value if comparable?(left_value, right_value) + if comparable?(left_value, right_value) + left_value < right_value + else + nil + end end end class Lte < Comparator def check(left_value, right_value) - left_value <= right_value if comparable?(left_value, right_value) + if comparable?(left_value, right_value) + left_value <= right_value + else + nil + end end end end diff --git a/lib/jmespath/nodes/condition.rb b/lib/jmespath/nodes/condition.rb index 42d151f..5b39a69 100644 --- a/lib/jmespath/nodes/condition.rb +++ b/lib/jmespath/nodes/condition.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -37,7 +35,7 @@ def initialize(left, right, child) @child = child end - def visit(_value) + def visit(value) nil end diff --git a/lib/jmespath/nodes/current.rb b/lib/jmespath/nodes/current.rb index fb571a6..8e37ac3 100644 --- a/lib/jmespath/nodes/current.rb +++ b/lib/jmespath/nodes/current.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/expression.rb b/lib/jmespath/nodes/expression.rb index fcd1b40..218fc02 100644 --- a/lib/jmespath/nodes/expression.rb +++ b/lib/jmespath/nodes/expression.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -10,7 +8,7 @@ def initialize(expression) @expression = expression end - def visit(_value) + def visit(value) self end @@ -24,3 +22,4 @@ def optimize end end end + diff --git a/lib/jmespath/nodes/field.rb b/lib/jmespath/nodes/field.rb index 1eaff1c..0f2df46 100644 --- a/lib/jmespath/nodes/field.rb +++ b/lib/jmespath/nodes/field.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -43,7 +41,9 @@ class ChainedField < Field def initialize(keys) @keys = keys @key_syms = keys.each_with_object({}) do |k, syms| - syms[k] = k.to_sym if k.respond_to?(:to_sym) + if k.respond_to?(:to_sym) + syms[k] = k.to_sym + end end end @@ -70,7 +70,10 @@ def chain(other) private - attr_reader :keys + def keys + @keys + end + end end end diff --git a/lib/jmespath/nodes/flatten.rb b/lib/jmespath/nodes/flatten.rb index b50294f..7d46ece 100644 --- a/lib/jmespath/nodes/flatten.rb +++ b/lib/jmespath/nodes/flatten.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -18,6 +16,8 @@ def visit(value) values.push(v) end end + else + nil end end diff --git a/lib/jmespath/nodes/function.rb b/lib/jmespath/nodes/function.rb index f616b94..6dfd3d1 100644 --- a/lib/jmespath/nodes/function.rb +++ b/lib/jmespath/nodes/function.rb @@ -1,9 +1,8 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes class Function < Node + FUNCTIONS = {} def initialize(children, options = {}) @@ -39,10 +38,12 @@ def initialize(name) private def maybe_raise(error_type, message) - raise error_type, message unless @disable_visit_errors + unless @disable_visit_errors + raise error_type, message + end end - def call(_args) + def call(args) nil end end @@ -51,9 +52,9 @@ module TypeChecker def get_type(value) if value.respond_to?(:to_str) STRING_TYPE - elsif [true, false].include?(value) + elsif value == true || value == false BOOLEAN_TYPE - elsif value.nil? + elsif value == nil NULL_TYPE elsif value.is_a?(Numeric) NUMBER_TYPE @@ -81,7 +82,7 @@ def get_type(value) NULL_TYPE => 'null', NUMBER_TYPE => 'number', OBJECT_TYPE => 'object', - STRING_TYPE => 'string' + STRING_TYPE => 'string', }.freeze end @@ -92,12 +93,12 @@ def call(args) if args.count == 1 value = args.first else - return maybe_raise Errors::InvalidArityError, 'function abs() expects one argument' + return maybe_raise Errors::InvalidArityError, "function abs() expects one argument" end - if value.is_a?(Numeric) + if Numeric === value value.abs else - maybe_raise Errors::InvalidTypeError, 'function abs() expects a number' + return maybe_raise Errors::InvalidTypeError, "function abs() expects a number" end end end @@ -109,21 +110,20 @@ def call(args) if args.count == 1 values = args.first else - return maybe_raise Errors::InvalidArityError, 'function avg() expects one argument' + return maybe_raise Errors::InvalidArityError, "function avg() expects one argument" end if values.respond_to?(:to_ary) values = values.to_ary return nil if values.empty? - - values.inject(0) do |total, n| - if n.is_a?(Numeric) + values.inject(0) do |total,n| + if Numeric === n total + n else - return maybe_raise Errors::InvalidTypeError, 'function avg() expects numeric values' + return maybe_raise Errors::InvalidTypeError, "function avg() expects numeric values" end end / values.size.to_f else - maybe_raise Errors::InvalidTypeError, 'function avg() expects a number' + return maybe_raise Errors::InvalidTypeError, "function avg() expects a number" end end end @@ -135,12 +135,12 @@ def call(args) if args.count == 1 value = args.first else - return maybe_raise Errors::InvalidArityError, 'function ceil() expects one argument' + return maybe_raise Errors::InvalidArityError, "function ceil() expects one argument" end - if value.is_a?(Numeric) + if Numeric === value value.ceil else - maybe_raise Errors::InvalidTypeError, 'function ceil() expects a numeric value' + return maybe_raise Errors::InvalidTypeError, "function ceil() expects a numeric value" end end end @@ -157,10 +157,10 @@ def call(args) elsif haystack.respond_to?(:to_ary) haystack.to_ary.any? { |e| Util.as_json(e) == needle } else - maybe_raise Errors::InvalidTypeError, 'contains expects 2nd arg to be a list' + return maybe_raise Errors::InvalidTypeError, "contains expects 2nd arg to be a list" end else - maybe_raise Errors::InvalidArityError, 'function contains() expects 2 arguments' + return maybe_raise Errors::InvalidArityError, "function contains() expects 2 arguments" end end end @@ -172,12 +172,12 @@ def call(args) if args.count == 1 value = args.first else - return maybe_raise Errors::InvalidArityError, 'function floor() expects one argument' + return maybe_raise Errors::InvalidArityError, "function floor() expects one argument" end - if value.is_a?(Numeric) + if Numeric === value value.floor else - maybe_raise Errors::InvalidTypeError, 'function floor() expects a numeric value' + return maybe_raise Errors::InvalidTypeError, "function floor() expects a numeric value" end end end @@ -189,7 +189,7 @@ def call(args) if args.count == 1 value = args.first else - return maybe_raise Errors::InvalidArityError, 'function length() expects one argument' + return maybe_raise Errors::InvalidArityError, "function length() expects one argument" end if value.respond_to?(:to_hash) value.to_hash.size @@ -198,29 +198,32 @@ def call(args) elsif value.respond_to?(:to_str) value.to_str.size else - maybe_raise Errors::InvalidTypeError, 'function length() expects string, array or object' + return maybe_raise Errors::InvalidTypeError, "function length() expects string, array or object" end end end class Map < Function + FUNCTIONS['map'] = self def call(args) - return maybe_raise Errors::InvalidArityError, 'function map() expects two arguments' if args.count != 2 - - if args[0].is_a?(Nodes::Expression) + if args.count != 2 + return maybe_raise Errors::InvalidArityError, "function map() expects two arguments" + end + if Nodes::Expression === args[0] expr = args[0] else - return maybe_raise Errors::InvalidTypeError, 'function map() expects the first argument to be an expression' + return maybe_raise Errors::InvalidTypeError, "function map() expects the first argument to be an expression" end if args[1].respond_to?(:to_ary) list = args[1].to_ary else - return maybe_raise Errors::InvalidTypeError, 'function map() expects the second argument to be an list' + return maybe_raise Errors::InvalidTypeError, "function map() expects the second argument to be an list" end list.map { |value| expr.eval(value) } end + end class MaxFunction < Function @@ -232,16 +235,15 @@ def call(args) if args.count == 1 values = args.first else - return maybe_raise Errors::InvalidArityError, 'function max() expects one argument' + return maybe_raise Errors::InvalidArityError, "function max() expects one argument" end if values.respond_to?(:to_ary) values = values.to_ary return nil if values.empty? - first = values.first first_type = get_type(first) - unless [NUMBER_TYPE, STRING_TYPE].include?(first_type) - msg = String.new('function max() expects numeric or string values') + unless first_type == NUMBER_TYPE || first_type == STRING_TYPE + msg = "function max() expects numeric or string values" return maybe_raise Errors::InvalidTypeError, msg end values.inject([first, first_type]) do |(max, max_type), v| @@ -249,13 +251,13 @@ def call(args) if max_type == v_type v > max ? [v, v_type] : [max, max_type] else - msg = String.new('function max() encountered a type mismatch in sequence: ') + msg = "function max() encountered a type mismatch in sequence: " msg << "#{max_type}, #{v_type}" return maybe_raise Errors::InvalidTypeError, msg end end.first else - maybe_raise Errors::InvalidTypeError, 'function max() expects an array' + return maybe_raise Errors::InvalidTypeError, "function max() expects an array" end end end @@ -269,16 +271,15 @@ def call(args) if args.count == 1 values = args.first else - return maybe_raise Errors::InvalidArityError, 'function min() expects one argument' + return maybe_raise Errors::InvalidArityError, "function min() expects one argument" end if values.respond_to?(:to_ary) values = values.to_ary return nil if values.empty? - first = values.first first_type = get_type(first) - unless [NUMBER_TYPE, STRING_TYPE].include?(first_type) - msg = String.new('function min() expects numeric or string values') + unless first_type == NUMBER_TYPE || first_type == STRING_TYPE + msg = "function min() expects numeric or string values" return maybe_raise Errors::InvalidTypeError, msg end values.inject([first, first_type]) do |(min, min_type), v| @@ -286,13 +287,13 @@ def call(args) if min_type == v_type v < min ? [v, v_type] : [min, min_type] else - msg = String.new('function min() encountered a type mismatch in sequence: ') + msg = "function min() encountered a type mismatch in sequence: " msg << "#{min_type}, #{v_type}" return maybe_raise Errors::InvalidTypeError, msg end end.first else - maybe_raise Errors::InvalidTypeError, 'function min() expects an array' + return maybe_raise Errors::InvalidTypeError, "function min() expects an array" end end end @@ -306,7 +307,7 @@ def call(args) if args.count == 1 TYPE_NAMES[get_type(args.first)] else - maybe_raise Errors::InvalidArityError, 'function type() expects one argument' + return maybe_raise Errors::InvalidArityError, "function type() expects one argument" end end end @@ -322,10 +323,10 @@ def call(args) elsif value.is_a?(Struct) value.members.map(&:to_s) else - maybe_raise Errors::InvalidTypeError, 'function keys() expects a hash' + return maybe_raise Errors::InvalidTypeError, "function keys() expects a hash" end else - maybe_raise Errors::InvalidArityError, 'function keys() expects one argument' + return maybe_raise Errors::InvalidArityError, "function keys() expects one argument" end end end @@ -343,10 +344,10 @@ def call(args) elsif value.respond_to?(:to_ary) value.to_ary else - maybe_raise Errors::InvalidTypeError, 'function values() expects an array or a hash' + return maybe_raise Errors::InvalidTypeError, "function values() expects an array or a hash" end else - maybe_raise Errors::InvalidArityError, 'function values() expects one argument' + return maybe_raise Errors::InvalidArityError, "function values() expects one argument" end end end @@ -359,14 +360,14 @@ def call(args) glue = args[0] values = args[1] if !glue.respond_to?(:to_str) - maybe_raise Errors::InvalidTypeError, 'function join() expects the first argument to be a string' + return maybe_raise Errors::InvalidTypeError, "function join() expects the first argument to be a string" elsif values.respond_to?(:to_ary) && values.to_ary.all? { |v| v.respond_to?(:to_str) } values.to_ary.join(glue) else - maybe_raise Errors::InvalidTypeError, 'function join() expects values to be an array of strings' + return maybe_raise Errors::InvalidTypeError, "function join() expects values to be an array of strings" end else - maybe_raise Errors::InvalidArityError, 'function join() expects an array of strings' + return maybe_raise Errors::InvalidArityError, "function join() expects an array of strings" end end end @@ -379,7 +380,7 @@ def call(args) value = args.first value.respond_to?(:to_str) ? value.to_str : value.to_json else - maybe_raise Errors::InvalidArityError, 'function to_string() expects one argument' + return maybe_raise Errors::InvalidArityError, "function to_string() expects one argument" end end end @@ -392,11 +393,11 @@ def call(args) begin value = Float(args.first) Integer(value) === value ? value.to_i : value - rescue StandardError + rescue nil end else - maybe_raise Errors::InvalidArityError, 'function to_number() expects one argument' + return maybe_raise Errors::InvalidArityError, "function to_number() expects one argument" end end end @@ -406,15 +407,15 @@ class SumFunction < Function def call(args) if args.count == 1 && args.first.respond_to?(:to_ary) - args.first.to_ary.inject(0) do |sum, n| - if n.is_a?(Numeric) + args.first.to_ary.inject(0) do |sum,n| + if Numeric === n sum + n else - return maybe_raise Errors::InvalidTypeError, 'function sum() expects values to be numeric' + return maybe_raise Errors::InvalidTypeError, "function sum() expects values to be numeric" end end else - maybe_raise Errors::InvalidArityError, 'function sum() expects one argument' + return maybe_raise Errors::InvalidArityError, "function sum() expects one argument" end end end @@ -423,10 +424,10 @@ class NotNullFunction < Function FUNCTIONS['not_null'] = self def call(args) - if args.count.positive? + if args.count > 0 args.find { |value| !value.nil? } else - maybe_raise Errors::InvalidArityError, 'function not_null() expects one or more arguments' + return maybe_raise Errors::InvalidArityError, "function not_null() expects one or more arguments" end end end @@ -443,28 +444,26 @@ def call(args) value = value.to_ary # every element in the list must be of the same type array_type = get_type(value[0]) - if array_type == STRING_TYPE || array_type == NUMBER_TYPE || value.size.zero? + if array_type == STRING_TYPE || array_type == NUMBER_TYPE || value.size == 0 # stable sort n = 0 value.sort_by do |v| value_type = get_type(v) if value_type != array_type - msg = 'function sort() expects values to be an array of only numbers, or only integers' + msg = "function sort() expects values to be an array of only numbers, or only integers" return maybe_raise Errors::InvalidTypeError, msg end n += 1 [v, n] end else - maybe_raise Errors::InvalidTypeError, - 'function sort() expects values to be an array of numbers or integers' + return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers" end else - maybe_raise Errors::InvalidTypeError, - 'function sort() expects values to be an array of numbers or integers' + return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers" end else - maybe_raise Errors::InvalidArityError, 'function sort() expects one argument' + return maybe_raise Errors::InvalidArityError, "function sort() expects one argument" end end end @@ -480,28 +479,27 @@ def call(args) values = args[0].to_ary expression = args[1] array_type = get_type(expression.eval(values[0])) - if array_type == STRING_TYPE || array_type == NUMBER_TYPE || values.size.zero? + if array_type == STRING_TYPE || array_type == NUMBER_TYPE || values.size == 0 # stable sort the list n = 0 values.sort_by do |value| value = expression.eval(value) value_type = get_type(value) if value_type != array_type - msg = 'function sort() expects values to be an array of only numbers, or only integers' + msg = "function sort() expects values to be an array of only numbers, or only integers" return maybe_raise Errors::InvalidTypeError, msg end n += 1 [value, n] end else - maybe_raise Errors::InvalidTypeError, - 'function sort() expects values to be an array of numbers or integers' + return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers" end else - maybe_raise Errors::InvalidTypeError, 'function sort_by() expects an array and an expression' + return maybe_raise Errors::InvalidTypeError, "function sort_by() expects an array and an expression" end else - maybe_raise Errors::InvalidArityError, 'function sort_by() expects two arguments' + return maybe_raise Errors::InvalidArityError, "function sort_by() expects two arguments" end end end @@ -532,11 +530,11 @@ def compare_by(mode, *args) end else msg = "function #{mode}() expects an array and an expression" - maybe_raise Errors::InvalidTypeError, msg + return maybe_raise Errors::InvalidTypeError, msg end else msg = "function #{mode}() expects two arguments" - maybe_raise Errors::InvalidArityError, msg + return maybe_raise Errors::InvalidArityError, msg end end end @@ -572,17 +570,17 @@ def call(args) search_type = get_type(search) suffix_type = get_type(suffix) if search_type != STRING_TYPE - msg = 'function ends_with() expects first argument to be a string' + msg = "function ends_with() expects first argument to be a string" return maybe_raise Errors::InvalidTypeError, msg end if suffix_type != STRING_TYPE - msg = 'function ends_with() expects second argument to be a string' + msg = "function ends_with() expects second argument to be a string" return maybe_raise Errors::InvalidTypeError, msg end search.end_with?(suffix) else - msg = 'function ends_with() expects two arguments' - maybe_raise Errors::InvalidArityError, msg + msg = "function ends_with() expects two arguments" + return maybe_raise Errors::InvalidArityError, msg end end end @@ -598,17 +596,17 @@ def call(args) search_type = get_type(search) prefix_type = get_type(prefix) if search_type != STRING_TYPE - msg = 'function starts_with() expects first argument to be a string' + msg = "function starts_with() expects first argument to be a string" return maybe_raise Errors::InvalidTypeError, msg end if prefix_type != STRING_TYPE - msg = 'function starts_with() expects second argument to be a string' + msg = "function starts_with() expects second argument to be a string" return maybe_raise Errors::InvalidTypeError, msg end search.start_with?(prefix) else - msg = 'function starts_with() expects two arguments' - maybe_raise Errors::InvalidArityError, msg + msg = "function starts_with() expects two arguments" + return maybe_raise Errors::InvalidArityError, msg end end end @@ -617,8 +615,8 @@ class MergeFunction < Function FUNCTIONS['merge'] = self def call(args) - if args.count.zero? - msg = 'function merge() expects 1 or more arguments' + if args.count == 0 + msg = "function merge() expects 1 or more arguments" return maybe_raise Errors::InvalidArityError, msg end args.inject({}) do |h, v| @@ -631,8 +629,8 @@ class ReverseFunction < Function FUNCTIONS['reverse'] = self def call(args) - if args.count.zero? - msg = 'function reverse() expects 1 or more arguments' + if args.count == 0 + msg = "function reverse() expects 1 or more arguments" return maybe_raise Errors::InvalidArityError, msg end value = args.first @@ -641,8 +639,8 @@ def call(args) elsif value.respond_to?(:to_str) value.to_str.reverse else - msg = 'function reverse() expects an array or string' - maybe_raise Errors::InvalidTypeError, msg + msg = "function reverse() expects an array or string" + return maybe_raise Errors::InvalidTypeError, msg end end end diff --git a/lib/jmespath/nodes/index.rb b/lib/jmespath/nodes/index.rb index 9133a3d..5cf4120 100644 --- a/lib/jmespath/nodes/index.rb +++ b/lib/jmespath/nodes/index.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/literal.rb b/lib/jmespath/nodes/literal.rb index 05ce78d..b73baa9 100644 --- a/lib/jmespath/nodes/literal.rb +++ b/lib/jmespath/nodes/literal.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -10,7 +8,7 @@ def initialize(value) @value = value end - def visit(_value) + def visit(value) @value end end diff --git a/lib/jmespath/nodes/multi_select_hash.rb b/lib/jmespath/nodes/multi_select_hash.rb index 852a11c..38bb295 100644 --- a/lib/jmespath/nodes/multi_select_hash.rb +++ b/lib/jmespath/nodes/multi_select_hash.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/multi_select_list.rb b/lib/jmespath/nodes/multi_select_list.rb index 0029a35..66ffc7b 100644 --- a/lib/jmespath/nodes/multi_select_list.rb +++ b/lib/jmespath/nodes/multi_select_list.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/not.rb b/lib/jmespath/nodes/not.rb index 908d6df..4af3b1a 100644 --- a/lib/jmespath/nodes/not.rb +++ b/lib/jmespath/nodes/not.rb @@ -1,8 +1,7 @@ -# frozen_string_literal: true - module JMESPath module Nodes class Not < Node + def initialize(expression) @expression = expression end @@ -14,6 +13,7 @@ def visit(value) def optimize self.class.new(@expression.optimize) end + end end end diff --git a/lib/jmespath/nodes/or.rb b/lib/jmespath/nodes/or.rb index 97512ae..42114ec 100644 --- a/lib/jmespath/nodes/or.rb +++ b/lib/jmespath/nodes/or.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/pipe.rb b/lib/jmespath/nodes/pipe.rb index 20d0d6f..44c8023 100644 --- a/lib/jmespath/nodes/pipe.rb +++ b/lib/jmespath/nodes/pipe.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/nodes/projection.rb b/lib/jmespath/nodes/projection.rb index 6724785..bed2090 100644 --- a/lib/jmespath/nodes/projection.rb +++ b/lib/jmespath/nodes/projection.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -14,7 +12,9 @@ def visit(value) list = [] targets.each do |v| vv = @projection.visit(v) - list << vv unless vv.nil? + unless vv.nil? + list << vv + end end list end @@ -30,7 +30,7 @@ def optimize private - def extract_targets(_left_value) + def extract_targets(left_value) nil end end @@ -45,7 +45,11 @@ def visit(value) class ArrayProjection < Projection def extract_targets(target) - target.to_ary if target.respond_to?(:to_ary) + if target.respond_to?(:to_ary) + target.to_ary + else + nil + end end def fast_instance @@ -63,6 +67,8 @@ def extract_targets(target) target.to_hash.values elsif target.is_a?(Struct) target.values + else + nil end end diff --git a/lib/jmespath/nodes/slice.rb b/lib/jmespath/nodes/slice.rb index eab4c1d..2db7461 100644 --- a/lib/jmespath/nodes/slice.rb +++ b/lib/jmespath/nodes/slice.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes @@ -8,35 +6,34 @@ def initialize(start, stop, step) @start = start @stop = stop @step = step - raise Errors::InvalidValueError, 'slice step cannot be 0' if @step == 0 + raise Errors::InvalidValueError.new('slice step cannot be 0') if @step == 0 end def visit(value) - if (value = if value.respond_to?(:to_str) - value.to_str - else - value.respond_to?(:to_ary) ? value.to_ary : nil - end) + if (value = value.respond_to?(:to_str) ? value.to_str : value.respond_to?(:to_ary) ? value.to_ary : nil) start, stop, step = adjust_slice(value.size, @start, @stop, @step) result = [] - i = start - if step.positive? + if step > 0 + i = start while i < stop result << value[i] i += step end else + i = start while i > stop result << value[i] i += step end end value.respond_to?(:to_str) ? result.join : result + else + nil end end def optimize - if (@step.nil? || @step == 1) && @start && @stop && @start.positive? && @stop > @start + if (@step.nil? || @step == 1) && @start && @stop && @start > 0 && @stop > @start SimpleSlice.new(@start, @stop) else self @@ -46,29 +43,31 @@ def optimize private def adjust_slice(length, start, stop, step) - step = 1 if step.nil? + if step.nil? + step = 1 + end - start = if start.nil? - step.negative? ? length - 1 : 0 - else - adjust_endpoint(length, start, step) - end + if start.nil? + start = step < 0 ? length - 1 : 0 + else + start = adjust_endpoint(length, start, step) + end - stop = if stop.nil? - step.negative? ? -1 : length - else - adjust_endpoint(length, stop, step) - end + if stop.nil? + stop = step < 0 ? -1 : length + else + stop = adjust_endpoint(length, stop, step) + end [start, stop, step] end def adjust_endpoint(length, endpoint, step) - if endpoint.negative? + if endpoint < 0 endpoint += length - endpoint = step.negative? ? -1 : 0 if endpoint.negative? + endpoint = step < 0 ? -1 : 0 if endpoint < 0 endpoint elsif endpoint >= length - step.negative? ? length - 1 : length + step < 0 ? length - 1 : length else endpoint end @@ -81,12 +80,10 @@ def initialize(start, stop) end def visit(value) - if (value = if value.respond_to?(:to_str) - value.to_str - else - value.respond_to?(:to_ary) ? value.to_ary : nil - end) + if (value = value.respond_to?(:to_str) ? value.to_str : value.respond_to?(:to_ary) ? value.to_ary : nil) value[@start, @stop - @start] + else + nil end end end diff --git a/lib/jmespath/nodes/subexpression.rb b/lib/jmespath/nodes/subexpression.rb index 3a17a32..81e23dd 100644 --- a/lib/jmespath/nodes/subexpression.rb +++ b/lib/jmespath/nodes/subexpression.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath # @api private module Nodes diff --git a/lib/jmespath/parser.rb b/lib/jmespath/parser.rb index 99e860c..8d0960d 100644 --- a/lib/jmespath/parser.rb +++ b/lib/jmespath/parser.rb @@ -1,29 +1,28 @@ -# frozen_string_literal: true - require 'set' module JMESPath # @api private class Parser + AFTER_DOT = Set.new([ - Lexer::T_IDENTIFIER, # foo.bar - Lexer::T_QUOTED_IDENTIFIER, # foo."bar" - Lexer::T_STAR, # foo.* - Lexer::T_LBRACE, # foo{a: 0} - Lexer::T_LBRACKET, # foo[1] - Lexer::T_FILTER # foo.[?bar==10] - ]) + Lexer::T_IDENTIFIER, # foo.bar + Lexer::T_QUOTED_IDENTIFIER, # foo."bar" + Lexer::T_STAR, # foo.* + Lexer::T_LBRACE, # foo{a: 0} + Lexer::T_LBRACKET, # foo[1] + Lexer::T_FILTER, # foo.[?bar==10] + ]) NUM_COLON_RBRACKET = Set.new([ - Lexer::T_NUMBER, - Lexer::T_COLON, - Lexer::T_RBRACKET - ]) + Lexer::T_NUMBER, + Lexer::T_COLON, + Lexer::T_RBRACKET, + ]) COLON_RBRACKET = Set.new([ - Lexer::T_COLON, - Lexer::T_RBRACKET - ]) + Lexer::T_COLON, + Lexer::T_RBRACKET, + ]) CURRENT_NODE = Nodes::Current.new @@ -35,7 +34,7 @@ def initialize(options = {}) # @param [String] expression def parse(expression) - tokens = @lexer.tokenize(expression) + tokens = @lexer.tokenize(expression) stream = TokenStream.new(expression, tokens) result = expr(stream) if stream.token.type != Lexer::T_EOF @@ -60,7 +59,9 @@ def method_missing(method_name, *args) # @param [Integer] rbp Right binding power def expr(stream, rbp = 0) left = send("nud_#{stream.token.type}", stream) - left = send("led_#{stream.token.type}", stream, left) while rbp < (stream.token.binding_power || 0) + while rbp < (stream.token.binding_power || 0) + left = send("led_#{stream.token.type}", stream, left) + end left end @@ -82,8 +83,9 @@ def nud_not(stream) def nud_lparen(stream) stream.next result = expr(stream, 0) - raise Errors::SyntaxError, 'Unclosed `(`' if stream.token.type != Lexer::T_RPAREN - + if stream.token.type != Lexer::T_RPAREN + raise Errors::SyntaxError, 'Unclosed `(`' + end stream.next result end @@ -107,14 +109,15 @@ def nud_identifier(stream) end def nud_lbrace(stream) - valid_keys = Set.new(%i[quoted_identifier identifier]) - stream.next(match: valid_keys) + valid_keys = Set.new([:quoted_identifier, :identifier]) + stream.next(match:valid_keys) pairs = [] - loop do + begin pairs << parse_key_value_pair(stream) - stream.next(match: valid_keys) if stream.token.type == :comma - break unless stream.token.type != :rbrace - end + if stream.token.type == :comma + stream.next(match:valid_keys) + end + end while stream.token.type != :rbrace stream.next Nodes::MultiSelectHash.new(pairs) end @@ -122,7 +125,7 @@ def nud_lbrace(stream) def nud_lbracket(stream) stream.next type = stream.token.type - if %i[number colon].include?(type) + if type == :number || type == :colon parse_array_index_expression(stream) elsif type == :star && stream.lookahead(1).type == :rbracket parse_wildcard_array(stream) @@ -164,7 +167,7 @@ def led_comparator(stream, left) end def led_dot(stream, left) - stream.next(match: AFTER_DOT) + stream.next(match:AFTER_DOT) if stream.token.type == :star parse_wildcard_object(stream, left) else @@ -176,8 +179,9 @@ def led_dot(stream, left) def led_filter(stream, left) stream.next expression = expr(stream) - raise Errors::SyntaxError, 'expected a closing rbracket for the filter' if stream.token.type != Lexer::T_RBRACKET - + if stream.token.type != Lexer::T_RBRACKET + raise Errors::SyntaxError, 'expected a closing rbracket for the filter' + end stream.next rhs = parse_projection(stream, Token::BINDING_POWER[Lexer::T_FILTER]) left ||= CURRENT_NODE @@ -193,9 +197,9 @@ def led_flatten(stream, left) end def led_lbracket(stream, left) - stream.next(match: Set.new(%i[number colon star])) + stream.next(match: Set.new([:number, :colon, :star])) type = stream.token.type - if %i[number colon].include?(type) + if type == :number || type == :colon right = parse_array_index_expression(stream) Nodes::Subexpression.new(left, right) else @@ -205,7 +209,7 @@ def led_lbracket(stream, left) def led_lparen(stream, left) args = [] - if left.is_a?(Nodes::Function::FunctionName) + if Nodes::Function::FunctionName === left name = left.name else raise Errors::SyntaxError, 'invalid function invocation' @@ -213,10 +217,12 @@ def led_lparen(stream, left) stream.next while stream.token.type != :rparen args << expr(stream, 0) - stream.next if stream.token.type == :comma + if stream.token.type == :comma + stream.next + end end stream.next - Nodes::Function.create(name, args, disable_visit_errors: @disable_visit_errors) + Nodes::Function.create(name, args, :disable_visit_errors => @disable_visit_errors) end def led_or(stream, left) @@ -243,22 +249,20 @@ def parse_array_index_expression(stream) parts = [nil, nil, nil] expected = NUM_COLON_RBRACKET - loop do - case stream.token.type - when Lexer::T_COLON + begin + if stream.token.type == Lexer::T_COLON pos += 1 expected = NUM_COLON_RBRACKET - when Lexer::T_NUMBER + elsif stream.token.type == Lexer::T_NUMBER parts[pos] = stream.token.value expected = COLON_RBRACKET end stream.next(match: expected) - break unless stream.token.type != Lexer::T_RBRACKET - end + end while stream.token.type != Lexer::T_RBRACKET stream.next # consume the closing bracket - if pos.zero? + if pos == 0 # no colons found, this is a single index extraction Nodes::Index.new(parts[0]) elsif pos > 2 @@ -282,21 +286,22 @@ def parse_dot(stream, binding_power) def parse_key_value_pair(stream) key = stream.token.value - stream.next(match: Set.new([:colon])) + stream.next(match:Set.new([:colon])) stream.next Nodes::MultiSelectHash::KeyValuePair.new(key, expr(stream)) end def parse_multi_select_list(stream) nodes = [] - loop do + begin nodes << expr(stream) if stream.token.type == :comma stream.next - raise Errors::SyntaxError, 'expression epxected, found rbracket' if stream.token.type == :rbracket + if stream.token.type == :rbracket + raise Errors::SyntaxError, 'expression epxected, found rbracket' + end end - break unless stream.token.type != :rbracket - end + end while stream.token.type != :rbracket stream.next Nodes::MultiSelectList.new(nodes) end @@ -306,9 +311,9 @@ def parse_projection(stream, binding_power) if stream.token.binding_power < 10 CURRENT_NODE elsif type == :dot - stream.next(match: AFTER_DOT) + stream.next(match:AFTER_DOT) parse_dot(stream, binding_power) - elsif %i[lbracket filter].include?(type) + elsif type == :lbracket || type == :filter expr(stream, binding_power) else raise Errors::SyntaxError, 'syntax error after projection' @@ -316,7 +321,7 @@ def parse_projection(stream, binding_power) end def parse_wildcard_array(stream, left = nil) - stream.next(match: Set.new([:rbracket])) + stream.next(match:Set.new([:rbracket])) stream.next left ||= CURRENT_NODE right = parse_projection(stream, Token::BINDING_POWER[:star]) @@ -329,5 +334,6 @@ def parse_wildcard_object(stream, left = nil) right = parse_projection(stream, Token::BINDING_POWER[:star]) Nodes::ObjectProjection.new(left, right) end + end end diff --git a/lib/jmespath/runtime.rb b/lib/jmespath/runtime.rb index 3e4e523..171cfa7 100644 --- a/lib/jmespath/runtime.rb +++ b/lib/jmespath/runtime.rb @@ -1,8 +1,7 @@ -# frozen_string_literal: true - module JMESPath # @api private class Runtime + # @api private DEFAULT_PARSER = CachingParser @@ -67,5 +66,6 @@ def default_parser(options) DEFAULT_PARSER.new(options) end end + end end diff --git a/lib/jmespath/token.rb b/lib/jmespath/token.rb index 1749b22..303d5e9 100644 --- a/lib/jmespath/token.rb +++ b/lib/jmespath/token.rb @@ -1,36 +1,35 @@ -# frozen_string_literal: true - module JMESPath # @api private class Token < Struct.new(:type, :value, :position, :binding_power) + NULL_TOKEN = Token.new(:eof, '', nil) BINDING_POWER = { - Lexer::T_UNKNOWN => 0, - Lexer::T_EOF => 0, + Lexer::T_UNKNOWN => 0, + Lexer::T_EOF => 0, Lexer::T_QUOTED_IDENTIFIER => 0, - Lexer::T_IDENTIFIER => 0, - Lexer::T_RBRACKET => 0, - Lexer::T_RPAREN => 0, - Lexer::T_COMMA => 0, - Lexer::T_RBRACE => 0, - Lexer::T_NUMBER => 0, - Lexer::T_CURRENT => 0, - Lexer::T_EXPREF => 0, - Lexer::T_COLON => 0, - Lexer::T_PIPE => 1, - Lexer::T_OR => 2, - Lexer::T_AND => 3, - Lexer::T_COMPARATOR => 5, - Lexer::T_FLATTEN => 9, - Lexer::T_STAR => 20, - Lexer::T_FILTER => 21, - Lexer::T_DOT => 40, - Lexer::T_NOT => 45, - Lexer::T_LBRACE => 50, - Lexer::T_LBRACKET => 55, - Lexer::T_LPAREN => 60 - }.freeze + Lexer::T_IDENTIFIER => 0, + Lexer::T_RBRACKET => 0, + Lexer::T_RPAREN => 0, + Lexer::T_COMMA => 0, + Lexer::T_RBRACE => 0, + Lexer::T_NUMBER => 0, + Lexer::T_CURRENT => 0, + Lexer::T_EXPREF => 0, + Lexer::T_COLON => 0, + Lexer::T_PIPE => 1, + Lexer::T_OR => 2, + Lexer::T_AND => 3, + Lexer::T_COMPARATOR => 5, + Lexer::T_FLATTEN => 9, + Lexer::T_STAR => 20, + Lexer::T_FILTER => 21, + Lexer::T_DOT => 40, + Lexer::T_NOT => 45, + Lexer::T_LBRACE => 50, + Lexer::T_LBRACKET => 55, + Lexer::T_LPAREN => 60, + } # @param [Symbol] type # @param [Mixed] value @@ -38,5 +37,6 @@ class Token < Struct.new(:type, :value, :position, :binding_power) def initialize(type, value, position) super(type, value, position, BINDING_POWER[type]) end + end end diff --git a/lib/jmespath/token_stream.rb b/lib/jmespath/token_stream.rb index ff07c19..76f5f0b 100644 --- a/lib/jmespath/token_stream.rb +++ b/lib/jmespath/token_stream.rb @@ -1,8 +1,7 @@ -# frozen_string_literal: true - module JMESPath # @api private class TokenStream + # @param [String] expression # @param [Array] tokens def initialize(expression, tokens) @@ -36,7 +35,8 @@ def lookahead(count) def inspect str = [] @tokens.each do |token| - str << format('%3d %-15s %s', token.position, token.type, token.value.inspect) + str << "%3d %-15s %s" % + [token.position, token.type, token.value.inspect] end str.join("\n") end @@ -50,10 +50,11 @@ def _next def validate_match(token, match) if match && !match.include?(token.type) - raise Errors::SyntaxError, 'type missmatch' + raise Errors::SyntaxError, "type missmatch" else token end end + end end diff --git a/lib/jmespath/util.rb b/lib/jmespath/util.rb index 0794b78..73ac86d 100644 --- a/lib/jmespath/util.rb +++ b/lib/jmespath/util.rb @@ -1,19 +1,18 @@ -# frozen_string_literal: true - module JMESPath # @api private module Util class << self + # Determines if a value is false as defined by JMESPath: # # https://github.com/jmespath/jmespath.site/blob/master/docs/proposals/improved-filters.rst#and-expressions-1 # def falsey?(value) !value || - (value.respond_to?(:to_ary) && value.to_ary.empty?) || - (value.respond_to?(:to_hash) && value.to_hash.empty?) || - (value.respond_to?(:to_str) && value.to_str.empty?) || - (value.respond_to?(:entries) && value.entries.none?) + (value.respond_to?(:to_ary) && value.to_ary.empty?) || + (value.respond_to?(:to_hash) && value.to_hash.empty?) || + (value.respond_to?(:to_str) && value.to_str.empty?) || + (value.respond_to?(:entries) && !value.entries.any?) # final case necessary to support Enumerable and Struct end diff --git a/lib/jmespath/version.rb b/lib/jmespath/version.rb index cdbc8ff..e372ea3 100644 --- a/lib/jmespath/version.rb +++ b/lib/jmespath/version.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module JMESPath - VERSION = File.read(File.expand_path('../../VERSION', __dir__)).strip + VERSION = File.read(File.expand_path('../../../VERSION', __FILE__)).strip end diff --git a/spec/compliance_spec.rb b/spec/compliance_spec.rb index 9c9bd12..9c8fcb7 100644 --- a/spec/compliance_spec.rb +++ b/spec/compliance_spec.rb @@ -1,9 +1,8 @@ -# frozen_string_literal: true - require 'spec_helper' describe 'Compliance' do Dir.glob('spec/{compliance,legacy}/*.json').each do |path| + test_file = File.basename(path).split('.').first next if test_file == 'benchmarks' next if ENV['TEST_FILE'] && ENV['TEST_FILE'] != test_file @@ -12,24 +11,26 @@ JMESPath.load_json(path).each do |scenario| describe("Given #{scenario['given'].to_json}") do scenario['cases'].each do |test_case| + if test_case['error'] it "the expression #{test_case['expression'].inspect} raises a #{test_case['error']} error" do + error_class = case test_case['error'] - when 'runtime' then JMESPath::Errors::RuntimeError - when 'syntax' then JMESPath::Errors::SyntaxError - when 'invalid-type' then JMESPath::Errors::InvalidTypeError - when 'invalid-value' then JMESPath::Errors::InvalidValueError - when 'invalid-arity' then JMESPath::Errors::InvalidArityError - when 'unknown-function' then JMESPath::Errors::UnknownFunctionError - else raise "unhandled error type #{test_case['error']}" - end + when 'runtime' then JMESPath::Errors::RuntimeError + when 'syntax' then JMESPath::Errors::SyntaxError + when 'invalid-type' then JMESPath::Errors::InvalidTypeError + when 'invalid-value' then JMESPath::Errors::InvalidValueError + when 'invalid-arity' then JMESPath::Errors::InvalidArityError + when 'unknown-function' then JMESPath::Errors::UnknownFunctionError + else raise "unhandled error type #{test_case['error']}" + end raised = nil begin JMESPath.search(test_case['expression'], scenario['given']) - rescue JMESPath::Errors::Error => e - raised = e + rescue JMESPath::Errors::Error => error + raised = error end expect(raised).to be_kind_of(error_class) diff --git a/spec/compliance_without_errors_spec.rb b/spec/compliance_without_errors_spec.rb index 315537c..413ec91 100644 --- a/spec/compliance_without_errors_spec.rb +++ b/spec/compliance_without_errors_spec.rb @@ -1,35 +1,36 @@ -# frozen_string_literal: true - require 'spec_helper' describe 'Compliance' do - PARSER = JMESPath::Parser.new(disable_visit_errors: true) + PARSER = JMESPath::Parser.new(:disable_visit_errors => true) Dir.glob('spec/compliance/*.json').each do |path| describe(File.basename(path).split('.').first) do JMESPath.load_json(path).each do |scenario| describe("Given #{scenario['given'].inspect}") do scenario['cases'].each do |test_case| + if test_case['error'] if %w[invalid-type invalid-arity].include?(test_case['error']) it "the expression #{test_case['expression'].inspect} returns nil if disable_visit_errors is true" do + result = PARSER.parse(test_case['expression']).visit(scenario['given']) expect(result).to be_nil end else it "the expression #{test_case['expression'].inspect} raises a #{test_case['error']} error when parsing even if disable_visit_errors is true" do + error_class = case test_case['error'] - when 'syntax' then JMESPath::Errors::SyntaxError - when 'invalid-value' then JMESPath::Errors::InvalidValueError - when 'unknown-function' then JMESPath::Errors::UnknownFunctionError - else raise "unhandled error type #{test_case['error']}" - end + when 'syntax' then JMESPath::Errors::SyntaxError + when 'invalid-value' then JMESPath::Errors::InvalidValueError + when 'unknown-function' then JMESPath::Errors::UnknownFunctionError + else raise "unhandled error type #{test_case['error']}" + end raised = nil begin PARSER.parse(test_case['expression']) - rescue JMESPath::Errors::Error => e - raised = e + rescue JMESPath::Errors::Error => error + raised = error end expect(raised).to be_kind_of(error_class) diff --git a/spec/implicit_conversion_spec.rb b/spec/implicit_conversion_spec.rb index 640e8f8..9366843 100644 --- a/spec/implicit_conversion_spec.rb +++ b/spec/implicit_conversion_spec.rb @@ -1,14 +1,8 @@ -# frozen_string_literal: true - require 'spec_helper' module Wrapper def self.wrap(o) - if o.respond_to?(:to_ary) - Arrayish.new(o) - else - o.respond_to?(:to_hash) ? Hashish.new(o) : o - end + o.respond_to?(:to_ary) ? Arrayish.new(o) : o.respond_to?(:to_hash) ? Hashish.new(o) : o end end @@ -41,26 +35,29 @@ def to_hash module JMESPath describe '.search' do describe 'implicit conversion' do + it 'searches hash/array structures' do - data = Hashish.new({ 'foo' => { 'bar' => ['value'] } }) + data = Hashish.new({'foo' => {'bar' => ['value']}}) result = JMESPath.search('foo.bar', data) expect(result).to be_instance_of(Arrayish) expect(result.ary).to eq(['value']) end it 'searches with flatten' do - data = Hashish.new({ 'foo' => [[{ 'bar' => 0 }], [{ 'baz' => 0 }]] }) + data = Hashish.new({'foo' => [[{'bar' => 0}], [{'baz' => 0}]]}) result = JMESPath.search('foo[]', data) expect(result.size).to eq(2) expect(result[0]).to be_instance_of(Hashish) - expect(result[0].hash).to eq({ 'bar' => 0 }) + expect(result[0].hash).to eq({'bar' => 0}) expect(result[1]).to be_instance_of(Hashish) - expect(result[1].hash).to eq({ 'baz' => 0 }) + expect(result[1].hash).to eq({'baz' => 0}) end + end describe 'Compliance' do Dir.glob('spec/{compliance,legacy}/*.json').each do |path| + test_file = File.basename(path).split('.').first next if test_file == 'benchmarks' next if ENV['TEST_FILE'] && ENV['TEST_FILE'] != test_file @@ -69,12 +66,14 @@ module JMESPath JMESPath.load_json(path).each do |scenario| describe("Given #{scenario['given'].to_json}") do scenario['cases'].each do |test_case| - next if test_case['error'] - it "searching #{test_case['expression'].inspect} returns #{test_case['result'].to_json}" do - result = JMESPath.search(test_case['expression'], Wrapper.wrap(scenario['given'])) + if !test_case['error'] + it "searching #{test_case['expression'].inspect} returns #{test_case['result'].to_json}" do + result = JMESPath.search(test_case['expression'], Wrapper.wrap(scenario['given'])) + + expect(JMESPath::Util.as_json(result)).to eq(test_case['result']) + end - expect(JMESPath::Util.as_json(result)).to eq(test_case['result']) end end end @@ -82,5 +81,6 @@ module JMESPath end end end + end end diff --git a/spec/indifferent_access_spec.rb b/spec/indifferent_access_spec.rb index e6be9d6..8b2adb9 100644 --- a/spec/indifferent_access_spec.rb +++ b/spec/indifferent_access_spec.rb @@ -1,12 +1,11 @@ -# frozen_string_literal: true - require 'spec_helper' module JMESPath describe '.search' do describe 'indifferent access' do + it 'treats hashes indifferently with symbols/strings' do - data = { foo: { bar: { yuck: 'abc' } } } + data = {foo:{bar:{yuck:'abc'}}} expect(JMESPath.search('foo.bar.yuck', data)).to eq('abc') end @@ -27,6 +26,7 @@ module JMESPath ) expect(JMESPath.search('foo.baz.yuck', data)).to be(nil) end + end end end diff --git a/spec/jmespath_spec.rb b/spec/jmespath_spec.rb index 44fc1f5..207092c 100644 --- a/spec/jmespath_spec.rb +++ b/spec/jmespath_spec.rb @@ -1,25 +1,24 @@ -# frozen_string_literal: true - require 'spec_helper' module JMESPath describe '.search' do + it 'searches data' do expression = 'foo.bar' - data = { 'foo' => { 'bar' => 'value' } } + data = {'foo' => {'bar' => 'value'}} expect(JMESPath.search(expression, data)).to eq('value') end it 'accepts data as a Pathname' do file_path = File.join(File.dirname(__FILE__), 'fixtures', 'sample.json') file_path = Pathname.new(file_path) - expect(JMESPath.search('foo.*.baz', file_path)).to eq([1, 2, 3]) + expect(JMESPath.search('foo.*.baz', file_path)).to eq([1,2,3]) end it 'accepts data as an IO object' do file_path = File.join(File.dirname(__FILE__), 'fixtures', 'sample.json') File.open(file_path, 'r') do |file| - expect(JMESPath.search('foo.*.baz', file)).to eq([1, 2, 3]) + expect(JMESPath.search('foo.*.baz', file)).to eq([1,2,3]) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce420bb..dde4e71 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - # Using Bundler.require intentionally to simulate environments that have already # required a specific version of the `json` or `json_pure` gems. The actual version # loaded is decided by the specific gemfile being loaded from the gemfiles directory. diff --git a/tasks/benchmark.rake b/tasks/benchmark.rake index 7f9431e..2d33bef 100644 --- a/tasks/benchmark.rake +++ b/tasks/benchmark.rake @@ -1,17 +1,17 @@ -# frozen_string_literal: true - desc 'Runs the benchmark suite' task 'benchmark' do + require 'jmespath' require 'absolute_time' - runtime = JMESPath::Runtime.new(cache_expressions: !ENV['CACHE'].nil?) + runtime = JMESPath::Runtime.new(cache_expressions: !!ENV['CACHE']) # The benchmarks are taken from the boto/jmespath project from the # pref/ directory. Dir.glob('benchmark/*.json').each do |path| JMESPath.load_json(path).first.tap do |scenario| scenario['cases'].each do |test_case| + expression = test_case['expression'] data = scenario['given'] @@ -23,7 +23,8 @@ task 'benchmark' do end label = "#{scenario['description']} - #{test_case['name']}" - printf(format("%fms, %s\n", time * 1000, label)) + printf("%fms, %s\n" % [time * 1000, label]) + end end end @@ -31,5 +32,5 @@ end desc 'Runs the benchmark suite, with expression caching' task 'benchmark:cached' do - sh({ 'CACHE' => '1' }, 'bundle exec rake benchmark') + sh({"CACHE" => "1"}, "bundle exec rake benchmark") end diff --git a/tasks/test.rake b/tasks/test.rake index 0ffd74d..82bc371 100644 --- a/tasks/test.rake +++ b/tasks/test.rake @@ -1,16 +1,14 @@ -# frozen_string_literal: true - require 'rspec/core/rake_task' $RSPEC_OPTS = ENV['VERBOSE'] ? ' --format doc --color' : '' -desc 'Run unit tests' +desc "Run unit tests" RSpec::Core::RakeTask.new('test:unit') do |t| t.rspec_opts = "-I lib#{$RSPEC_OPTS}" t.exclude_pattern = 'spec/compliance_*.rb' end -desc 'Run compliance tests' +desc "Run compliance tests" RSpec::Core::RakeTask.new('test:compliance') do |t| t.rspec_opts = "-I lib#{$RSPEC_OPTS}" t.pattern = 'spec/compliance_*.rb'