liquid-tag-parser 1.6.1 → 1.7.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: 1f6acfa193f9ff74b8a5b9ec7f097541c51e0bc0
4
- data.tar.gz: cec8af085b61e195f3d1f963c44aa59b12a3fd11
3
+ metadata.gz: bd8c6f633da42e565f8c6e744f5de6385cb58ee5
4
+ data.tar.gz: 43fefa58e961df937b95fe110b11c7a6315ed2d9
5
5
  SHA512:
6
- metadata.gz: 4246db8db03ad8aa8d07dbfc7da6693dfd27ab4119ec1626703d3e778c4c3c3055d161ecd3d3d7a7f318853ee009f67b445d95b69e79c82b07575c1dfcb8e012
7
- data.tar.gz: a5d85f6d83e6b34dfd9d9abaec0ad310af13c5cee7e247b742a7e929beb48ebb130e92ea1f7e7a815d0d1052e82ee8c302a2261acf53d092a7b550734d1a4d73
6
+ metadata.gz: e6a50303cb1f2abf3ed5d807918b81682d264d91a87bf51d5c7ff3731131a7e559fb15530a49d884afd1cabb0f849ffa70560934972c80af01eb6840691fc5dc
7
+ data.tar.gz: c98e7886202657c54d46c9af31b4aac1cb60ab778f94af1920384cea4802d860c931e1a9fc012992edde64949b1f117691bb0bed9a588dc1820912f674644639
data/Gemfile CHANGED
@@ -1,8 +1,13 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2017 Jordon Bedwell - MIT License
3
+ # Encoding: utf-8
4
+
1
5
  source "https://rubygems.org"
2
6
  gemspec
3
7
 
4
8
  group :development do
5
- gem "pry", require: false
9
+ gem "pry", require: false
10
+ gem "rubocop", require: false
6
11
  gem "rake", require: false
7
12
  end
8
13
 
@@ -12,6 +12,7 @@ module Liquid
12
12
  attr_reader :args, :raw_args
13
13
  extend Forwardable::Extended
14
14
 
15
+ # --
15
16
  rb_delegate :each, to: :@args
16
17
  rb_delegate :key?, to: :@args
17
18
  rb_delegate :to_h, to: :@args
@@ -27,122 +28,200 @@ module Liquid
27
28
  rb_delegate :merge!, to: :@args
28
29
  rb_delegate :deep_merge, to: :@args
29
30
  rb_delegate :deep_merge!, to: :@args
30
- rb_delegate :args_with_indifferent_access, to: :@args, \
31
- alias_of: :with_indifferent_access
32
-
33
- FLOAT = /^\d+\.\d+$/
34
- BOOLEAN = /^(?<!\\)(\!|@)/
35
- NEGATIVE_BOOLEAN = /^(?<!\\)\!/
36
- BOOLEAN_QUOTE_REPLACEMENT = "\\1\\\\\\2"
37
- SHELLSPLIT = /\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m
38
- BOOLEAN_QUOTE = /('|")((?<!\\)@|(?<!\\)\!)/
39
- POSITIVE_BOOLEAN = /^(?<!\\)\@/
40
- ESCAPED_BOOLEAN = /\\(@|\!)/
41
- KEY = /\b(?<!\\):/
42
- INT = /^\d+$/
43
-
31
+ rb_delegate :args_with_indifferent_access, {
32
+ to: :@args, alias_of: :with_indifferent_access
33
+ }
34
+
35
+ # --
36
+ FALSE = "!"
37
+ FLOAT = %r!\A\d+\.\d+\Z!
38
+ QUOTE = %r!("|')([^\1]*)(\1)!
39
+ SPECIAL = %r!(?<\!\\)(@|\!|:|=)!
40
+ BOOL = %r!\A(?<\!\\)(\!|@)([\w:]+)\Z!
41
+ UNQUOTED_SPECIAL = %r!(?<\!\\)(://)!
42
+ SPECIAL_ESCAPED = %r!\\(@|\!|:|=)!
43
+ KEY = %r!\b(?<\!\\):!
44
+ INT = %r!^\d+$!
45
+ TRUE = "@"
46
+
47
+ # This is taken from Ruby 2.4 standard library.
48
+ SHELLSPLIT = %r!\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|
49
+ \\.)*)"|(\\.?)|(\S))(\s|\z)?!mx
50
+
51
+ # --
44
52
  def initialize(raw, defaults: {}, sep: "=")
45
53
  @sep = sep
54
+ @unescaped_sep = sep
46
55
  @rsep = Regexp.escape(sep)
47
- @escaped_sep_regexp = /\\#{@rsep}/
48
- @sep_regexp = /\b(?<!\\)#{@rsep}/
56
+ @escaped_sep_regexp = %r!\\(#{@rsep})!
57
+ @sep_regexp = %r!\b(?<\!\\)(#{@rsep})!
49
58
  @escaped_sep = "\\#{@sep}"
50
- @defaults = defaults
51
- @args = {}
59
+ @args = defaults
52
60
  @raw = raw
53
61
 
54
62
  parse
55
63
  end
56
64
 
57
- def to_html(skip: [], hash: false)
58
- out = @args.each_with_object(hash ? {} : []) do |(k, v), o|
59
- next if k == :argv1
60
- next if v.is_a?(Array)
61
- next if skip.include?(k)
62
- next if v.is_a?(Hash)
63
- next if v == false
64
-
65
- o[k] = v if hash
66
- unless hash
67
- o << (v == true ? k.to_s : "#{k}=\"#{v}\"")
68
- end
65
+ # --
66
+ # Consumes a block and wraps around reusably on arguments.
67
+ # @return [Hash<Symbol,Object>,Array<String>]
68
+ # --
69
+ def skippable_loop(skip: [], hash: false)
70
+ @args.each_with_object(hash ? {} : []) do |(k, v), o|
71
+ skip_in_html?(k: k, v: v, skips: skip) ? next : yield([k, v], o)
72
+ end
73
+ end
74
+
75
+ # --
76
+ # @param [Array<Symbol>] skip keys to skip.
77
+ # Converts the arguments into an HTML attribute string.
78
+ # @return [String]
79
+ # --
80
+ def to_html(skip: [])
81
+ skippable_loop(skip: skip, hash: false) do |(k, v), o|
82
+ o << (v == true ? k.to_s : "#{k}=\"#{v}\"")
83
+ end.join(" ")
84
+ end
85
+
86
+ # --
87
+ # @param [Array<Symbol>] skip keys to skip.
88
+ # @param [true,false] for_html skip non-html values.
89
+ # Converts arguments into an HTML hash (or to arguments).
90
+ # @return [Hash]
91
+ # --
92
+ def to_h(skip: [], html: false)
93
+ return @args unless html
94
+ skippable_loop(skip: skip, hash: true) do |(k, v), o|
95
+ o[k] = v
96
+ end
97
+ end
98
+
99
+ # --
100
+ # @param [String] k the key
101
+ # @param [Object] v the value
102
+ # @param [Array<Symbol>] skips personal skips.
103
+ # Determines if we should skip in HTML.
104
+ # @return [true,false]
105
+ # --
106
+ private
107
+ def skip_in_html?(k:, v:, skips: [])
108
+ k == :argv1 || v.is_a?(Array) || skips.include?(k) \
109
+ || v.is_a?(Hash) || v == false
110
+ end
111
+
112
+ # --
113
+ # @return [true,nil] a truthy value.
114
+ # @param [Integer] i the current iteration.
115
+ # @param [String] keys the keys that will be split.
116
+ # @param [String] val the value.
117
+ # --
118
+ private
119
+ def argv1(i:, k:, v:)
120
+ if i.zero? && k.empty? && v !~ BOOL && v !~ @sep_regexp
121
+ @args[:argv1] = convert(v)
69
122
  end
123
+ end
70
124
 
71
- hash ? out : out.join(" ")
125
+ # --
126
+ # @return [Array<String,true|false>]
127
+ # Allows you to flip a value based on condition.
128
+ # @param [String] v the value.
129
+ # --
130
+ private
131
+ def flip_kv_bool(v)
132
+ [
133
+ v.gsub(BOOL, "\\2"),
134
+ v.start_with?(TRUE) ? true : false,
135
+ ]
72
136
  end
73
137
 
138
+ # --
139
+ # @param [Array<Symbol>] keys the keys.
140
+ # Builds a sub-hash or returns parent hash.
141
+ # @return [Hash]
142
+ # --
74
143
  private
75
- def argv1(args)
76
- val = args[0]
77
- hash = {}
78
-
79
- # !"@true" && !"key1:key2=val" but "argv1 @true key1:key2=val"
80
- if val !~ BOOLEAN && val !~ KEY && val !~ @sep_regexp
81
- hash = {
82
- argv1: args.delete_at(0)
83
- }
144
+ def build_hash(keys)
145
+ out = @args
146
+
147
+ if keys.size > 1
148
+ out = @args[keys[0]] ||= {}
149
+ keys[1...-1].each do |sk|
150
+ out = out[sk] ||= {}
151
+ end
84
152
  end
85
153
 
86
- return args, hash
154
+ out
87
155
  end
88
156
 
157
+ # --
89
158
  private
90
159
  def parse
91
- args, hash = argv1(from_shellwords)
92
- @args = @defaults.deep_merge(args.each_with_object(hash) do |k, h, out = h|
160
+ from_shellwords.each_with_index do |k, i|
93
161
  keys, _, val = k.rpartition(@sep_regexp)
162
+ val.gsub!(@escaped_sep_regexp, @unescaped_sep)
163
+ val.gsub!(SPECIAL_ESCAPED, "\\1")
94
164
 
95
- val = val.gsub(@escaped_sep_regexp, @sep) # Unescape \\=
96
- keys = val.gsub(BOOLEAN, "") if keys.empty? && val =~ BOOLEAN # @true
97
- keys, val = val, nil if keys.empty? # key val
165
+ next if argv1(i: i, k: keys, v: val)
166
+ keys, val = flip_kv_bool(val) if val =~ BOOL && keys.empty?
167
+ keys, val = val, nil if keys.empty?
98
168
  keys = keys.split(KEY).map(&:to_sym)
99
169
 
100
- if keys.size > 1
101
- h = h[keys[0]] ||= {}
102
- keys[1...-1].each do |sk|
103
- h = h[sk] ||= {}
104
- end
105
- end
106
-
107
- val = val.to_i if val =~ INT # key=1
108
- val = val.to_f if val =~ FLOAT # key=0.1
109
- val = false if val == "false" # key=false
110
- val = false if val =~ NEGATIVE_BOOLEAN # !false
111
- val = true if val =~ POSITIVE_BOOLEAN # @true
112
- val = true if val == "true" # key=true
113
-
114
- if val.is_a?(String)
115
- then val = val.gsub(ESCAPED_BOOLEAN, "\\1")
116
- end
170
+ set_val({
171
+ v: convert(val),
172
+ hash: build_hash(keys),
173
+ k: keys.last,
174
+ })
175
+ end
176
+ end
117
177
 
118
- key = keys.last.to_sym
119
- h[key] << val if h[key].is_a?(Array)
120
- h[key] = [h[key]].flatten << val if h[key] && !h[key].is_a?(Array)
121
- h[key] = val unless h[key]
178
+ # --
179
+ private
180
+ def set_val(k:, v:, hash:)
181
+ hash[k] << v if hash[k].is_a?(Array)
182
+ hash[k] = [hash[k]].flatten << v if hash[k] && !hash[k].is_a?(Array)
183
+ hash[k] = v unless hash[k]
184
+ end
122
185
 
123
- out
124
- end)
186
+ # --
187
+ # @return [true,false,Float,Integer]
188
+ # Convert a value to a native value.
189
+ # --
190
+ private
191
+ def convert(val)
192
+ return val.to_f if val =~ FLOAT
193
+ return val.to_i if val =~ INT
194
+ val
125
195
  end
126
196
 
197
+ # --
198
+ # Wraps into `#shellsplit`, and first substitutes some values.
199
+ # @return [Array<String>]
200
+ # --
127
201
  private
128
202
  def from_shellwords
129
- shellsplit(@raw.gsub(/('|")([^\1]+)\1/) do |v|
130
- v.gsub(BOOLEAN_QUOTE, BOOLEAN_QUOTE_REPLACEMENT).gsub(@sep_regexp, @escaped_sep)
131
- end)
203
+ shellsplit(
204
+ @raw.gsub(SPECIAL, "\\\\\\1")
205
+ .gsub(UNQUOTED_SPECIAL, "\\\\\\1")
206
+ .gsub(@sep_regexp, @escaped_sep))
132
207
  end
133
208
 
134
- # Because Shellwords.shellwords on < 2.4 has problems
135
- # with quotes and \\, we ported this back, this pretty
136
- # much the same thing except we replace some of the
137
- # questionable code like `String.new`
209
+ # --
210
+ # @see Shellwords.shellsplit
211
+ # Because Shellwords.shellwords on < 2.4 has problems with
212
+ # quotes and \\, we ported this back, this pretty much the
213
+ # same thing except we replace some of the questionable
214
+ # code like `String.new`
215
+ # --
138
216
  private
139
217
  def shellsplit(line)
140
218
  out, field = [], ""
141
219
 
220
+ # rubocop:disable Metrics/ParameterLists
142
221
  line.scan(SHELLSPLIT) do |w, s, d, e, g, se|
143
222
  raise ArgumentError, "Unmatched double quote: #{line.inspect}" if g
144
- field = field + (w || s || (d && d.gsub(/\\([$`"\\\n])/, '\\1')) \
145
- || e.gsub(/\\(.)/, '\\1'))
223
+ field = field + (w || s || (d&.gsub(%r!\\([$`"\\\n])!,
224
+ '\\1')) || e.gsub(%r!\\(.)!, '\\1'))
146
225
 
147
226
  if se
148
227
  out << field
@@ -5,7 +5,7 @@
5
5
  module Liquid
6
6
  class Tag
7
7
  class Parser
8
- VERSION = "1.6.1"
8
+ VERSION = "1.7.0"
9
9
  end
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liquid-tag-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordon Bedwell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-01 00:00:00.000000000 Z
11
+ date: 2017-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec