awesome_xml 1.1.0 → 1.2.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: c56c2831ab0626cb308dc5dea679f2f854077101
4
- data.tar.gz: f25a4b311f2cad636f5deba9797cfd48fb014e8d
3
+ metadata.gz: '09184adda9b06ea9f6219d70c4a73639e1f24a82'
4
+ data.tar.gz: e6fa8cb7358a7e0eef58e3c5ba312e104c5df4a4
5
5
  SHA512:
6
- metadata.gz: 27448af39a7950d1c96a3e1d814037acaeb63dc08ac2cd2d2034889899feefacd3fc1702ffffdbdd6d409262a7034dbc531ea5b7b0e393f75db57eaf70997d85
7
- data.tar.gz: 84179c85be80e1543a7b53e3c7a1d823086126c99322b7cce5f6916564caedb0b1fdcf6d8d342c4bc5fb626fe5fd5d884db389ec0e935e40c58729ca77324f65
6
+ metadata.gz: 0334bed7e8863a5ce46ccc245e72266f66e561f200d610a7d79868454f5761a7742055ebe6fc8f4d147d194742eca7c144155f4117e9a53dd169be8cb3669b59
7
+ data.tar.gz: 68870e318cbba35b3046d5a9acd411e9d77c300e611340b4616343f79c0dc04043352749973282133a0beffc921c13c91be19d35596fadbfd92d988512e191c4
data/README.md CHANGED
@@ -42,7 +42,7 @@ Its arguments are
42
42
  - an options hash (optional)
43
43
 
44
44
  The type can either be a native type given in the form of a symbol (currently supported are `:text`,
45
- `:integer`, `:float`, `:duration` and `:date_time`), or a custom class. You can also pass in a string containing
45
+ `:integer`, `:float`, `:duration`, `:date_time` and `:void`), or a custom class. You can also pass in a string containing
46
46
  a class name in case the class constant is not yet defined at the time you run the `.node` method.
47
47
  More about that later.
48
48
 
@@ -271,6 +271,48 @@ class MyDocument
271
271
  end
272
272
  ```
273
273
 
274
+ ## Node names
275
+
276
+ There are three options you can use in case you want to parse not the content of an element or attribute,
277
+ but the name of it: `:element_name`, `:attribute_name`, `:self_name`. Those will parse the name of the element or
278
+ the attribute specified by the name of the node or by an `:xpath` option, or the name of the current node itself.
279
+
280
+ Let's look at an example:
281
+
282
+ ```xml
283
+ <document>
284
+ <heap1>
285
+ <item ref='a'/>
286
+ </heap1>
287
+ <heap2>
288
+ <item ref='b'/>
289
+ </heap2>
290
+ </document>
291
+ ```
292
+
293
+ Now let's assume you want your hash to equal
294
+ ```ruby
295
+ { items: [ { ref: 'a', heap: 'heap1' }, { ref: 'b', heap: 'heap2' } ] }
296
+ ```
297
+
298
+ You can solve this by using `element_name: true`:
299
+
300
+ ```ruby
301
+ class MyDocument
302
+ include AwesomeXML
303
+
304
+ set_context 'document'
305
+ node :items, 'Item', array: true, xpath: '//item'
306
+
307
+ class Item
308
+ include AwesomeXML
309
+
310
+ node :ref, :text, attribute: true
311
+ node :heap, :text, element_name: true, xpath: '../'
312
+ end
313
+ end
314
+ ```
315
+
274
316
  Awesome, right? You've got a few more notches you can kick it up, though.
275
317
 
276
318
  ## Passing blocks
@@ -477,7 +519,9 @@ or doesn't even exist. For the former, use `:default_empty`, for the latter, use
477
519
 
478
520
  ## More node types
479
521
 
480
- Let's talk about duration nodes. As you may remember, `:duration` is of the native types for `.node`.
522
+ ### Duration nodes
523
+
524
+ As you may remember, `:duration` is of the native types for `.node`.
481
525
  They return `ActiveSupport::Duration` objects, which interact freely with each other and with `Time` and
482
526
  `DateTime` objects.
483
527
  The special thing about them is that they take a *mandatory* `:format` option. There, you can specify the
@@ -496,3 +540,35 @@ but when the numbers are single digit, it looks like `'2m1'`. In this case, just
496
540
  `parse_length`. Everything up to the following character (or the end of the duration string) will be
497
541
  treated as going into the parsed value. The format string that would parse you the correct duration
498
542
  would be `'{M}m{S}'`.
543
+
544
+ ### Void nodes
545
+
546
+ This type is used if you don't actually want to parse anything. For example, if you simply want to count the
547
+ occurrence of a tag. The result of the parsing operation is simply the node(s) itself. Suppose your XML document
548
+ is this:
549
+
550
+ ```xml
551
+ <document>
552
+ <items>
553
+ <item>1234</item>
554
+ <item>4321</item>
555
+ <item>5678</item>
556
+ </items>
557
+ </document>
558
+ ```
559
+
560
+ And you want your ruby hash to be
561
+ ```ruby
562
+ { number_of_items: 3 }
563
+ ```
564
+
565
+ This will do it for you:
566
+
567
+ ```ruby
568
+ class MyDocument
569
+ include AwesomeXML
570
+
571
+ set_context 'document/items'
572
+ node(:number_of_items, :void, element: 'item', array: true) { |nodes| nodes.size }
573
+ end
574
+ ```
@@ -9,6 +9,7 @@ FILES = %w(
9
9
  types/float
10
10
  types/duration
11
11
  types/date_time
12
+ types/void
12
13
  type
13
14
  class_methods
14
15
  duration/chunk_parser
@@ -70,6 +70,10 @@ module AwesomeXML
70
70
  @public_nodes ||= []
71
71
  end
72
72
 
73
+ def parsing_type?
74
+ false
75
+ end
76
+
73
77
  private
74
78
 
75
79
  def register(node_name, privateness)
@@ -4,12 +4,18 @@
4
4
  # interface for types that the `AwesomeXML::NodeEvaluator` expects.
5
5
  module AwesomeXML
6
6
  module NativeType
7
+ def self.included(base)
8
+ base.class_eval do
9
+ base.extend(AwesomeXML::NativeType::ClassMethods)
10
+ end
11
+ end
12
+
7
13
  attr_reader :string, :options
8
14
  private :string, :options
9
15
 
10
16
  # Native type instances are initialized with a `Nokogiri::XML` object and an options hash.
11
- def initialize(node, options = {})
12
- @string = node&.text
17
+ def initialize(string, options)
18
+ @string = string
13
19
  @options = options
14
20
  end
15
21
 
@@ -19,6 +25,12 @@ module AwesomeXML
19
25
  @value ||= with_defaults { parse_value }
20
26
  end
21
27
 
28
+ module ClassMethods
29
+ def parsing_type?
30
+ true
31
+ end
32
+ end
33
+
22
34
  private
23
35
 
24
36
  def with_defaults(&block)
@@ -21,14 +21,19 @@ module AwesomeXML
21
21
  # type passed in in the form of a class that handles the conversion.
22
22
  def call
23
23
  if options[:array]
24
- all_nodes.map { |node| type_class.new(node, options).evaluate }
24
+ all_nodes.map { |node| type_class.new(content(node), options).evaluate }
25
25
  else
26
- type_class.new(first_node, options).evaluate
26
+ type_class.new(content(first_node), options).evaluate
27
27
  end
28
28
  end
29
29
 
30
30
  private
31
31
 
32
+ def content(node)
33
+ return node unless type_class.parsing_type?
34
+ (options[:element_name] || options[:attribute_name] || options[:self_name]) ? node&.name : node&.text
35
+ end
36
+
32
37
  def all_nodes
33
38
  xml_in_context&.xpath(xpath)
34
39
  end
@@ -3,40 +3,39 @@
3
3
  # This class's responsibility is to build an XPath from specified options.
4
4
  module AwesomeXML
5
5
  class NodeXPath
6
- attr_reader :node_name, :specific_xpath, :element_option, :attribute_option, :self_option, :array
7
- private :node_name, :specific_xpath, :element_option, :attribute_option, :self_option, :array
6
+ attr_reader :node_name, :options
7
+ private :node_name, :options
8
8
 
9
9
  # Initialize this class by providing the name of the `AwesomeXML` node and an options hash.
10
10
  # For more information on how the options work, please refer to the README.
11
11
  def initialize(node_name, options)
12
12
  @node_name = node_name
13
- @specific_xpath = options[:xpath]
14
- @element_option = options[:element]
15
- @attribute_option = options[:attribute]
16
- @self_option = options[:self]
17
- @look_for = options[:look_for]
18
- @array = options[:array]
13
+ @options = options
19
14
  end
20
15
 
21
16
  # Returns a String representing an XPath built from the options passed in at initialization time.
22
17
  def xpath
23
- specific_xpath || xpath_by_tag_type
18
+ options[:xpath] || xpath_by_tag_type
24
19
  end
25
20
 
26
21
  private
27
22
 
28
23
  def xpath_by_tag_type
29
- if attribute_option
30
- "./@#{tag_name(attribute_option)}"
31
- elsif self_option
24
+ if options[:attribute]
25
+ "./@#{tag_name(options[:attribute])}"
26
+ elsif options[:attribute_name]
27
+ "./@#{tag_name(true)}"
28
+ elsif options[:self] || options[:self_name]
32
29
  "."
30
+ elsif options[:element_name]
31
+ "./#{tag_name(true)}"
33
32
  else
34
- "./#{tag_name(element_option)}"
33
+ "./#{tag_name(options[:element])}"
35
34
  end
36
35
  end
37
36
 
38
37
  def node_name_singular
39
- array ? node_name.to_s.singularize.to_sym : node_name
38
+ options[:array] ? node_name.to_s.singularize.to_sym : node_name
40
39
  end
41
40
 
42
41
  def tag_name(option)
@@ -9,7 +9,8 @@ module AwesomeXML
9
9
  integer: AwesomeXML::Integer,
10
10
  float: AwesomeXML::Float,
11
11
  duration: AwesomeXML::Duration,
12
- date_time: AwesomeXML::DateTime
12
+ date_time: AwesomeXML::DateTime,
13
+ void: AwesomeXML::Void
13
14
  }.freeze
14
15
 
15
16
  # Takes a type (Symbol, String or Class) passed in from a `.node` method call and the
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A class that knows how to not parse but simply pass on a node.
4
+ module AwesomeXML
5
+ class Void
6
+ attr_reader :node
7
+ private :node
8
+
9
+ def initialize(node, options)
10
+ @node = node
11
+ @options = options
12
+ end
13
+
14
+ def evaluate
15
+ node
16
+ end
17
+
18
+ def self.parsing_type?
19
+ false
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awesome_xml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Lublasser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-01 00:00:00.000000000 Z
11
+ date: 2017-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -121,6 +121,7 @@ files:
121
121
  - lib/awesome_xml/types/float.rb
122
122
  - lib/awesome_xml/types/integer.rb
123
123
  - lib/awesome_xml/types/text.rb
124
+ - lib/awesome_xml/types/void.rb
124
125
  homepage: https://github.com/fromAtoB/awesome_xml
125
126
  licenses:
126
127
  - MIT