Class: Lkml::Simple::DictParser

Inherits:
Object
  • Object
show all
Defined in:
lib/lkml/simple.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDictParser

Returns a new instance of DictParser.



100
101
102
103
104
105
# File 'lib/lkml/simple.rb', line 100

def initialize
  @parent_key = nil
  @level = 0
  @base_indent = " " * 2
  @latest_node = Tree::DocumentNode
end

Instance Attribute Details

#base_indentObject

Returns the value of attribute base_indent.



98
99
100
# File 'lib/lkml/simple.rb', line 98

def base_indent
  @base_indent
end

#latest_nodeObject

Returns the value of attribute latest_node.



98
99
100
# File 'lib/lkml/simple.rb', line 98

def latest_node
  @latest_node
end

#levelObject

Returns the value of attribute level.



98
99
100
# File 'lib/lkml/simple.rb', line 98

def level
  @level
end

#parent_keyObject

Returns the value of attribute parent_key.



98
99
100
# File 'lib/lkml/simple.rb', line 98

def parent_key
  @parent_key
end

Class Method Details

.parse_token(key, value, force_quote, prefix: "", suffix: "") ⇒ Object



292
293
294
295
296
297
298
299
300
# File 'lib/lkml/simple.rb', line 292

def self.parse_token(key, value, force_quote, prefix: "", suffix: "")
  if force_quote || Keys::QUOTED_LITERAL_KEYS.include?(key)
    Tree::QuotedSyntaxToken.new(value, nil, prefix, suffix)
  elsif Keys::EXPR_BLOCK_KEYS.include?(key)
    Tree::ExpressionSyntaxToken.new(value.strip, nil, prefix, suffix)
  else
    Tree::SyntaxToken.new(value, nil, prefix, suffix)
  end
end

Instance Method Details

#decrease_levelObject



112
113
114
# File 'lib/lkml/simple.rb', line 112

def decrease_level
  @level -= 1
end

#expand_list(key, values) ⇒ Object



166
167
168
169
170
171
172
173
# File 'lib/lkml/simple.rb', line 166

def expand_list(key, values)
  if key == "filters"
    Simple.flatten([resolve_filters(values)])
  else
    singular_key = Keys.singularize(key)
    Simple.flatten(values.map { |v| parse_any(singular_key, v) })
  end
end

#increase_levelObject



107
108
109
110
# File 'lib/lkml/simple.rb', line 107

def increase_level
  @latest_node = nil
  @level += 1
end

#indentObject



116
117
118
# File 'lib/lkml/simple.rb', line 116

def indent
  @level.positive? ? @base_indent * @level : ""
end

#newline_indentObject



120
121
122
# File 'lib/lkml/simple.rb', line 120

def newline_indent
  "\n#{indent}"
end

#parse(obj) ⇒ Object



160
161
162
163
164
# File 'lib/lkml/simple.rb', line 160

def parse(obj)
  nodes = obj.map { |key, value| parse_any(key.to_s, value) }
  container = Tree::ContainerNode.new(items: Simple.flatten(nodes).freeze)
  Tree::DocumentNode.new(container)
end

#parse_any(key, value) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/lkml/simple.rb', line 175

def parse_any(key, value)
  case value
  when String
    parse_pair(key, value)
  when Array
    if plural_key?(key)
      expand_list(key, value)
    else
      parse_list(key, value)
    end
  when Hash
    h = value.transform_keys(&:to_s)
    name = if Keys::KEYS_WITH_NAME_FIELDS.include?(key) || !h.key?("name")
             nil
           else
             h.delete("name")
           end
    parse_block(key, h, name)
  else
    raise TypeError, "Value must be a string, list, tuple, or dict."
  end
end

#parse_block(key, items, name = nil) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/lkml/simple.rb', line 198

def parse_block(key, items, name = nil)
  prev_parent_key = @parent_key
  @parent_key = key
  latest_node_at_level = @latest_node
  increase_level
  child_nodes = items.map { |k, v| parse_any(k.to_s, v) }
  decrease_level
  @latest_node = latest_node_at_level
  @parent_key = prev_parent_key

  container = Tree::ContainerNode.new(items: Simple.flatten(child_nodes).freeze)

  block_prefix = if @latest_node && @latest_node != Tree::DocumentNode
                   "\n#{newline_indent}"
                 else
                   prefix
                 end

  node = Tree::BlockNode.new(
    type: Tree::SyntaxToken.new(key.to_s, nil, block_prefix),
    left_brace: Tree::LeftCurlyBrace.new("{", nil, (name ? " " : ""), ""),
    right_brace: Tree::RightCurlyBrace.new(
      "}", nil, (container.items.empty? ? "" : newline_indent), ""
    ),
    name: (name ? Tree::SyntaxToken.new(name.to_s) : nil),
    container: container
  )
  @latest_node = Tree::BlockNode
  node
end

#parse_list(key, values) ⇒ Object



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/lkml/simple.rb', line 229

def parse_list(key, values)
  force_quote = key == "suggestions"
  prev_parent_key = @parent_key
  @parent_key = key

  type_token = Tree::SyntaxToken.new(key.to_s, nil, prefix)
  pair_mode = values[0] && !values[0].is_a?(String) && !values[0].is_a?(Integer)

  items = []
  if pair_mode || values.length >= 5
    trailing_comma = Tree::Comma.new(",", nil, "", "")
    increase_level
    if pair_mode
      values.each do |h|
        h = h.transform_keys(&:to_s)
        raise ArgumentError, "Expected single-key hash in list pair" unless h.size == 1

        k, val = h.first
        items << parse_pair(k, val)
      end
    else
      values.each do |value|
        items << DictParser.parse_token(key, value.to_s, force_quote, prefix: newline_indent)
      end
    end
    decrease_level
    right_bracket = Tree::RightBracket.new("]", nil, newline_indent, "")
    node = Tree::ListNode.new(
      type: type_token,
      left_bracket: Tree::LeftBracket.new("[", nil, "", ""),
      items: items.freeze,
      right_bracket: right_bracket,
      trailing_comma: trailing_comma
    )
  else
    values.each_with_index do |value, i|
      pref = i.zero? ? "" : " "
      items << DictParser.parse_token(key, value.to_s, force_quote, prefix: pref)
    end
    node = Tree::ListNode.new(
      type: type_token,
      left_bracket: Tree::LeftBracket.new("[", nil, "", ""),
      items: items.freeze,
      right_bracket: Tree::RightBracket.new("]", nil, "", "")
    )
  end

  @parent_key = prev_parent_key
  @latest_node = Tree::ListNode
  node
end

#parse_pair(key, value) ⇒ Object



281
282
283
284
285
286
287
288
289
290
# File 'lib/lkml/simple.rb', line 281

def parse_pair(key, value)
  force_quote = @parent_key == "filters" && key != "field"
  value_syntax_token = DictParser.parse_token(key.to_s, value.to_s, force_quote)
  node = Tree::PairNode.new(
    type: Tree::SyntaxToken.new(key.to_s, nil, prefix),
    value: value_syntax_token
  )
  @latest_node = Tree::PairNode
  node
end

#plural_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


134
135
136
137
138
139
140
141
142
143
# File 'lib/lkml/simple.rb', line 134

def plural_key?(key)
  singular_key = Keys.singularize(key)
  return false unless Keys::PLURAL_KEYS.include?(singular_key)

  return false if singular_key == "allowed_value" && @parent_key&.sub(/s+\z/, "") == "access_grant"

  return false if @parent_key == "query" && singular_key != "filters"

  true
end

#prefixObject



124
125
126
127
128
129
130
131
132
# File 'lib/lkml/simple.rb', line 124

def prefix
  if @latest_node == Tree::DocumentNode
    ""
  elsif @latest_node == Tree::BlockNode
    "\n#{newline_indent}"
  else
    newline_indent
  end
end

#resolve_filters(values) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/lkml/simple.rb', line 145

def resolve_filters(values)
  first = values[0]
  if first.key?("name")
    values.map do |value|
      value = value.dup
      name = value.delete("name")
      parse_block("filter", value, name)
    end
  elsif first.key?("field") && first.key?("value")
    values.map { |value| parse_block("filters", value.dup, nil) }
  else
    parse_list("filters", values)
  end
end