micromicro 0.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +65 -29
  5. data/lib/micro_micro/collectible.rb +15 -0
  6. data/lib/micro_micro/collections/base_collection.rb +18 -13
  7. data/lib/micro_micro/collections/items_collection.rb +7 -0
  8. data/lib/micro_micro/collections/properties_collection.rb +20 -6
  9. data/lib/micro_micro/collections/relationships_collection.rb +33 -0
  10. data/lib/micro_micro/document.rb +36 -44
  11. data/lib/micro_micro/helpers.rb +82 -0
  12. data/lib/micro_micro/implied_property.rb +2 -0
  13. data/lib/micro_micro/item.rb +78 -52
  14. data/lib/micro_micro/parsers/base_implied_property_parser.rb +29 -0
  15. data/lib/micro_micro/parsers/base_property_parser.rb +9 -14
  16. data/lib/micro_micro/parsers/date_time_parser.rb +60 -31
  17. data/lib/micro_micro/parsers/date_time_property_parser.rb +20 -29
  18. data/lib/micro_micro/parsers/embedded_markup_property_parser.rb +7 -17
  19. data/lib/micro_micro/parsers/implied_name_property_parser.rb +17 -58
  20. data/lib/micro_micro/parsers/implied_photo_property_parser.rb +23 -51
  21. data/lib/micro_micro/parsers/implied_url_property_parser.rb +13 -42
  22. data/lib/micro_micro/parsers/plain_text_property_parser.rb +11 -18
  23. data/lib/micro_micro/parsers/url_property_parser.rb +29 -37
  24. data/lib/micro_micro/parsers/value_class_pattern_parser.rb +29 -55
  25. data/lib/micro_micro/property.rb +73 -68
  26. data/lib/micro_micro/{relation.rb → relationship.rb} +19 -16
  27. data/lib/micro_micro/version.rb +3 -1
  28. data/lib/micromicro.rb +37 -22
  29. data/micromicro.gemspec +14 -9
  30. metadata +23 -31
  31. data/.editorconfig +0 -14
  32. data/.gitignore +0 -34
  33. data/.gitmodules +0 -3
  34. data/.reek.yml +0 -8
  35. data/.rspec +0 -2
  36. data/.rubocop +0 -3
  37. data/.rubocop.yml +0 -25
  38. data/.ruby-version +0 -1
  39. data/.simplecov +0 -11
  40. data/.travis.yml +0 -19
  41. data/Gemfile +0 -14
  42. data/Rakefile +0 -18
  43. data/lib/micro_micro/collections/relations_collection.rb +0 -23
@@ -1,68 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Parsers
3
- class ImpliedPhotoPropertyParser < BasePropertyParser
4
- # @see microformats2 Parsing Specification section 1.3.5
5
- # @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
5
+ class ImpliedPhotoPropertyParser < BaseImpliedPropertyParser
6
+ CSS_SELECTORS_ARRAY = ['> img[src]:only-of-type', '> object[data]:only-of-type'].freeze
7
+
6
8
  HTML_ELEMENTS_MAP = {
7
9
  'img' => 'src',
8
10
  'object' => 'data'
9
11
  }.freeze
10
12
 
11
- # @return [String, nil]
13
+ # @see https://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
14
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_an_img_element_for_src_and_alt
15
+ #
16
+ # @return [String, Hash{Symbol => String}, nil]
12
17
  def value
13
- @value ||= begin
14
- return unless resolved_value
15
- return resolved_value unless value_node.matches?('img[alt]')
16
-
17
- {
18
- value: resolved_value,
19
- alt: value_node['alt'].strip
20
- }
21
- end
18
+ @value ||=
19
+ if attribute_value
20
+ return attribute_value unless candidate_node.matches?('img[alt]')
21
+
22
+ {
23
+ value: attribute_value,
24
+ alt: candidate_node['alt'].strip
25
+ }
26
+ end
22
27
  end
23
28
 
24
29
  private
25
30
 
26
- # @return [Array<String>]
27
- def attribute_values
28
- @attribute_values ||= begin
29
- HTML_ELEMENTS_MAP.map do |element, attribute|
30
- node if node.matches?("#{element}[#{attribute}]")
31
- end.compact
32
- end
33
- end
34
-
35
- # @return [String, nil]
36
- def resolved_value
37
- @resolved_value ||= Absolutely.to_abs(base: node.document.url, relative: unresolved_value.strip) if unresolved_value
38
- end
31
+ # @return [Array]
32
+ def child_nodes
33
+ nodes = [node.at_css(*CSS_SELECTORS_ARRAY)]
39
34
 
40
- # @return [String, nil]
41
- def unresolved_value
42
- @unresolved_value ||= value_node[HTML_ELEMENTS_MAP[value_node.name]] if value_node
43
- end
44
-
45
- # @return [Nokogiri::XML::Element, nil]
46
- def value_node
47
- @value_node ||= begin
48
- return attribute_values.first if attribute_values.any?
49
-
50
- HTML_ELEMENTS_MAP.each do |element, attribute|
51
- child_node = node.at_css("> #{element}[#{attribute}]:only-of-type")
52
-
53
- return child_node if child_node && !Item.item_node?(child_node) && element == child_node.name && child_node[attribute]
54
- end
55
-
56
- if node.element_children.one? && !Item.item_node?(node.first_element_child)
57
- HTML_ELEMENTS_MAP.each do |element, attribute|
58
- child_node = node.first_element_child.at_css("> #{element}[#{attribute}]:only-of-type")
59
-
60
- return child_node if child_node && !Item.item_node?(child_node) && element == child_node.name && child_node[attribute]
61
- end
62
- end
35
+ nodes << node.first_element_child.at_css(*CSS_SELECTORS_ARRAY) if node.element_children.one?
63
36
 
64
- nil
65
- end
37
+ nodes.compact.reject { |child_node| Helpers.item_node?(child_node) }
66
38
  end
67
39
  end
68
40
  end
@@ -1,60 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Parsers
3
- class ImpliedUrlPropertyParser < BasePropertyParser
4
- # @see microformats2 Parsing Specification section 1.3.5
5
- # @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
5
+ class ImpliedUrlPropertyParser < BaseImpliedPropertyParser
6
+ CSS_SELECTORS_ARRAY = ['> a[href]:only-of-type', '> area[href]:only-of-type'].freeze
7
+
6
8
  HTML_ELEMENTS_MAP = {
7
9
  'a' => 'href',
8
10
  'area' => 'href'
9
11
  }.freeze
10
12
 
13
+ # @see https://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
14
+ #
11
15
  # @return [String, nil]
12
16
  def value
13
- @value ||= resolved_value
17
+ @value ||= attribute_value
14
18
  end
15
19
 
16
20
  private
17
21
 
18
- # @return [Array<String>]
19
- def attribute_values
20
- @attribute_values ||= begin
21
- HTML_ELEMENTS_MAP.map do |element, attribute|
22
- node if node.matches?("#{element}[#{attribute}]")
23
- end.compact
24
- end
25
- end
26
-
27
- # @return [String, nil]
28
- def resolved_value
29
- @resolved_value ||= Absolutely.to_abs(base: node.document.url, relative: unresolved_value.strip) if unresolved_value
30
- end
31
-
32
- # @return [String, nil]
33
- def unresolved_value
34
- @unresolved_value ||= value_node[HTML_ELEMENTS_MAP[value_node.name]] if value_node
35
- end
36
-
37
- # @return [Nokogiri::XML::Element, nil]
38
- def value_node
39
- @value_node ||= begin
40
- return attribute_values.first if attribute_values.any?
41
-
42
- HTML_ELEMENTS_MAP.each do |element, attribute|
43
- child_node = node.at_css("> #{element}[#{attribute}]:only-of-type")
44
-
45
- return child_node if child_node && !Item.item_node?(child_node) && element == child_node.name && child_node[attribute]
46
- end
47
-
48
- if node.element_children.one? && !Item.item_node?(node.first_element_child)
49
- HTML_ELEMENTS_MAP.each do |element, attribute|
50
- child_node = node.first_element_child.at_css("> #{element}[#{attribute}]:only-of-type")
22
+ # @return [Array]
23
+ def child_nodes
24
+ nodes = [node.at_css(*CSS_SELECTORS_ARRAY)]
51
25
 
52
- return child_node if child_node && !Item.item_node?(child_node) && element == child_node.name && child_node[attribute]
53
- end
54
- end
26
+ nodes << node.first_element_child.at_css(*CSS_SELECTORS_ARRAY) if node.element_children.one?
55
27
 
56
- nil
57
- end
28
+ nodes.compact.reject { |child_node| Helpers.item_node?(child_node) }
58
29
  end
59
30
  end
60
31
  end
@@ -1,38 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Parsers
3
5
  class PlainTextPropertyParser < BasePropertyParser
4
- # @see microformats2 Parsing Specification section 1.3.1
5
- # @see http://microformats.org/wiki/microformats2-parsing#parsing_a_p-_property
6
6
  HTML_ATTRIBUTES_MAP = {
7
7
  'title' => %w[abbr link],
8
8
  'value' => %w[data input],
9
9
  'alt' => %w[area img]
10
10
  }.freeze
11
11
 
12
+ # @see https://microformats.org/wiki/microformats2-parsing#parsing_a_p-_property
13
+ #
12
14
  # @return [String]
13
15
  def value
14
- @value ||= begin
15
- return value_class_pattern_parser.value if value_class_pattern_parser.value?
16
- return attribute_values.first if attribute_values.any?
17
-
18
- super
19
- end
16
+ @value ||= value_class_pattern_value || attribute_value || super
20
17
  end
21
18
 
22
19
  private
23
20
 
24
- # @return [Array<String>]
25
- def attribute_values
26
- @attribute_values ||= begin
27
- HTML_ATTRIBUTES_MAP.map do |attribute, names|
28
- node[attribute] if names.include?(node.name) && node[attribute]
29
- end.compact
30
- end
21
+ # @return [String, nil]
22
+ def attribute_value
23
+ Helpers.attribute_value_from(node, HTML_ATTRIBUTES_MAP)
31
24
  end
32
25
 
33
- # @return [MicroMicro::Parsers::ValueClassPatternParser]
34
- def value_class_pattern_parser
35
- @value_class_pattern_parser ||= ValueClassPatternParser.new(node)
26
+ # @return [String, nil]
27
+ def value_class_pattern_value
28
+ ValueClassPatternParser.new(node).value
36
29
  end
37
30
  end
38
31
  end
@@ -1,8 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Parsers
3
5
  class UrlPropertyParser < BasePropertyParser
4
- # @see microformats2 Parsing Specification section 1.3.2
5
- # @see http://microformats.org/wiki/microformats2-parsing#parsing_a_u-_property
6
6
  HTML_ATTRIBUTES_MAP = {
7
7
  'href' => %w[a area link],
8
8
  'src' => %w[audio iframe img source video],
@@ -10,65 +10,57 @@ module MicroMicro
10
10
  'data' => %w[object]
11
11
  }.freeze
12
12
 
13
- # @see microformats2 Parsing Specification section 1.3.2
14
- # @see http://microformats.org/wiki/microformats2-parsing#parsing_a_u-_property
15
13
  EXTENDED_HTML_ATTRIBUTES_MAP = {
16
14
  'title' => %w[abbr],
17
15
  'value' => %w[data input]
18
16
  }.freeze
19
17
 
20
- # @see microformats2 Parsing Specification section 1.5
21
- # @see http://microformats.org/wiki/microformats2-parsing#parse_an_img_element_for_src_and_alt
18
+ # @see https://microformats.org/wiki/microformats2-parsing#parsing_a_u-_property
19
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_an_img_element_for_src_and_alt
22
20
  #
23
21
  # @return [String, Hash{Symbol => String}]
24
22
  def value
25
- @value ||= begin
26
- return resolved_value unless node.matches?('img[alt]')
27
-
28
- {
29
- value: resolved_value,
30
- alt: node['alt'].strip
31
- }
32
- end
23
+ @value ||=
24
+ if node.matches?('img[alt]')
25
+ {
26
+ value: resolved_value,
27
+ alt: node['alt'].strip
28
+ }
29
+ else
30
+ resolved_value
31
+ end
33
32
  end
34
33
 
35
34
  private
36
35
 
37
- def attribute_values
38
- @attribute_values ||= begin
39
- HTML_ATTRIBUTES_MAP.map do |attribute, names|
40
- node[attribute] if names.include?(node.name) && node[attribute]
41
- end.compact
42
- end
36
+ # @return [String, nil]
37
+ def attribute_value
38
+ Helpers.attribute_value_from(node, HTML_ATTRIBUTES_MAP)
43
39
  end
44
40
 
45
- def extended_attribute_values
46
- @extended_attribute_values ||= begin
47
- EXTENDED_HTML_ATTRIBUTES_MAP.map do |attribute, names|
48
- node[attribute] if names.include?(node.name) && node[attribute]
49
- end
50
- end.compact
41
+ # @return [String, nil]
42
+ def extended_attribute_value
43
+ Helpers.attribute_value_from(node, EXTENDED_HTML_ATTRIBUTES_MAP)
51
44
  end
52
45
 
53
46
  # @return [String]
54
47
  def resolved_value
55
- @resolved_value ||= Absolutely.to_abs(base: node.document.url, relative: unresolved_value.strip)
48
+ @resolved_value ||= node.document.resolve_relative_url(unresolved_value.strip)
56
49
  end
57
50
 
58
51
  # @return [String]
59
- def unresolved_value
60
- @unresolved_value ||= begin
61
- return attribute_values.first if attribute_values.any?
62
- return value_class_pattern_parser.value if value_class_pattern_parser.value?
63
- return extended_attribute_values.first if extended_attribute_values.any?
52
+ def text_content
53
+ Helpers.text_content_from(node)
54
+ end
64
55
 
65
- serialized_node.text
66
- end
56
+ # @return [String]
57
+ def unresolved_value
58
+ attribute_value || value_class_pattern_value || extended_attribute_value || text_content
67
59
  end
68
60
 
69
- # @return [MicroMicro::Parsers::ValueClassPatternParser]
70
- def value_class_pattern_parser
71
- @value_class_pattern_parser ||= ValueClassPatternParser.new(node)
61
+ # @return [String, nil]
62
+ def value_class_pattern_value
63
+ ValueClassPatternParser.new(node).value
72
64
  end
73
65
  end
74
66
  end
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Parsers
3
5
  class ValueClassPatternParser
4
- # @see Value Class Pattern sections 3 and 4
5
- # @see http://microformats.org/wiki/value-class-pattern#Basic_Parsing
6
- # @see http://microformats.org/wiki/value-class-pattern#Date_and_time_values
6
+ # @see https://microformats.org/wiki/value-class-pattern#Basic_Parsing
7
+ # @see https://microformats.org/wiki/value-class-pattern#Date_and_time_values
7
8
  HTML_ATTRIBUTES_MAP = {
8
9
  'alt' => %w[area img],
9
10
  'value' => %w[data],
@@ -11,82 +12,55 @@ module MicroMicro
11
12
  'datetime' => %w[del ins time]
12
13
  }.freeze
13
14
 
14
- # @param context [Nokogiri::XML::Element]
15
- # @param separator [String]
16
- def initialize(node, separator = '')
17
- @node = node
18
- @separator = separator
19
- end
20
-
21
- # @return [String, nil]
22
- def value
23
- @value ||= values.join(separator).strip if values?
24
- end
25
-
26
- # @return [Boolean]
27
- def value?
28
- value.present?
29
- end
30
-
31
- # @return [Array<String>]
32
- def values
33
- @values ||= value_nodes.map { |value_node| self.class.value_from(value_node) }.select(&:present?)
34
- end
35
-
36
- # @return [Boolean]
37
- def values?
38
- values.any?
39
- end
40
-
41
15
  # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
42
16
  # @param node_set [Nokogiri::XML::NodeSet]
43
17
  # @return [Nokogiri::XML::NodeSet]
44
- def self.nodes_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, []))
45
- context.each { |node| nodes_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet)
18
+ def self.node_set_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, []))
19
+ context.each { |node| node_set_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet)
46
20
 
47
- if context.is_a?(Nokogiri::XML::Element) && !Document.ignore_node?(context)
48
- if value_class_node?(context) || value_title_node?(context)
21
+ if context.is_a?(Nokogiri::XML::Element) && !Helpers.ignore_node?(context)
22
+ if Helpers.value_class_node?(context) || Helpers.value_title_node?(context)
49
23
  node_set << context
50
24
  else
51
- nodes_from(context.element_children, node_set)
25
+ node_set_from(context.element_children, node_set)
52
26
  end
53
27
  end
54
28
 
55
29
  node_set
56
30
  end
57
31
 
58
- # @param node [Nokogiri::XML::Element]
59
- # @return [Boolean]
60
- def self.value_class_node?(node)
61
- node.classes.include?('value')
62
- end
63
-
64
32
  # @param node [Nokogiri::XML::Element]
65
33
  # @return [String, nil]
66
34
  def self.value_from(node)
67
- return node['title'] if value_title_node?(node)
35
+ return node['title'] if Helpers.value_title_node?(node)
68
36
 
69
- HTML_ATTRIBUTES_MAP.each do |attribute, names|
70
- return node[attribute] if names.include?(node.name) && node[attribute]
71
- end
37
+ Helpers.attribute_value_from(node, HTML_ATTRIBUTES_MAP) || node.text
38
+ end
39
+
40
+ # @param context [Nokogiri::XML::Element]
41
+ # @param separator [String]
42
+ def initialize(node, separator = '')
43
+ @node = node
44
+ @separator = separator
45
+ end
72
46
 
73
- node.text
47
+ # @return [String, nil]
48
+ def value
49
+ @value ||= values.join(separator).strip if values.any?
74
50
  end
75
51
 
76
- # @param node [Nokogiri::XML::Element]
77
- # @return [Boolean]
78
- def self.value_title_node?(node)
79
- node.classes.include?('value-title')
52
+ # @return [Array<String>]
53
+ def values
54
+ @values ||=
55
+ self.class
56
+ .node_set_from(node)
57
+ .map { |value_node| self.class.value_from(value_node) }
58
+ .select(&:present?)
80
59
  end
81
60
 
82
61
  private
83
62
 
84
63
  attr_reader :node, :separator
85
-
86
- # @return [Nokogiri::XML::NodeSet]
87
- def value_nodes
88
- @value_nodes ||= self.class.nodes_from(node)
89
- end
90
64
  end
91
65
  end
92
66
  end
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  class Property
5
+ include Collectible
6
+
3
7
  PROPERTY_PARSERS_MAP = {
4
8
  'dt' => Parsers::DateTimePropertyParser,
5
9
  'e' => Parsers::EmbeddedMarkupPropertyParser,
@@ -7,16 +11,46 @@ module MicroMicro
7
11
  'u' => Parsers::UrlPropertyParser
8
12
  }.freeze
9
13
 
10
- attr_accessor :collection
11
14
  attr_reader :name, :node, :prefix
12
15
 
16
+ # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
17
+ # @return [Array<MicroMicro::Property>]
18
+ def self.from_context(context)
19
+ node_set_from(context).flat_map do |node|
20
+ Helpers.property_class_names_from(node).map { |token| new(node, token) }
21
+ end
22
+ end
23
+
24
+ # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
25
+ # @param node_set [Nokogiri::XML::NodeSet]
26
+ # @return [Nokogiri::XML::NodeSet]
27
+ def self.node_set_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, []))
28
+ context.each { |node| node_set_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet)
29
+
30
+ if context.is_a?(Nokogiri::XML::Element) && !Helpers.ignore_node?(context)
31
+ node_set << context if Helpers.property_node?(context)
32
+
33
+ node_set_from(context.element_children, node_set) unless Helpers.item_node?(context)
34
+ end
35
+
36
+ node_set
37
+ end
38
+
13
39
  # @param node [Nokogiri::XML::Element]
14
- # @param name [String]
15
- # @param prefix [String<dt, e, p, u>]
16
- def initialize(node, name:, prefix:)
40
+ # @param token [String]
41
+ def initialize(node, token)
17
42
  @node = node
18
- @name = name
19
- @prefix = prefix
43
+ @prefix, @name = token.split(/-/, 2)
44
+ end
45
+
46
+ # @return [Boolean]
47
+ def date_time_property?
48
+ prefix == 'dt'
49
+ end
50
+
51
+ # @return [Boolean]
52
+ def embedded_markup_property?
53
+ prefix == 'e'
20
54
  end
21
55
 
22
56
  # @return [Boolean]
@@ -24,91 +58,62 @@ module MicroMicro
24
58
  false
25
59
  end
26
60
 
61
+ # :nocov:
27
62
  # @return [String]
28
63
  def inspect
29
- format(%(#<#{self.class.name}:%#0x name: #{name.inspect}, prefix: #{prefix.inspect}, value: #{value.inspect}>), object_id)
64
+ "#<#{self.class}:#{format('%#0x', object_id)} " \
65
+ "name: #{name.inspect}, " \
66
+ "prefix: #{prefix.inspect}, " \
67
+ "value: #{value.inspect}>"
68
+ end
69
+ # :nocov:
70
+
71
+ # @return [MicroMicro::Item, nil]
72
+ def item
73
+ @item ||= Item.new(node) if item_node?
30
74
  end
31
75
 
32
76
  # @return [Boolean]
33
77
  def item_node?
34
- @item_node ||= Item.item_node?(node)
78
+ @item_node ||= Helpers.item_node?(node)
35
79
  end
36
80
 
37
- # @return [String, Hash, MicroMicro::Item]
38
- def value
39
- @value ||= begin
40
- return parser.value unless item_node?
41
-
42
- item.value = item_value
43
-
44
- item
45
- end
81
+ # @return [Boolean]
82
+ def plain_text_property?
83
+ prefix == 'p'
46
84
  end
47
85
 
48
86
  # @return [Boolean]
49
- def value?
50
- value.present?
87
+ def url_property?
88
+ prefix == 'u'
51
89
  end
52
90
 
53
- # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
54
- # @param node_set [Nokogiri::XML::NodeSet]
55
- # @return [Nokogiri::XML::NodeSet]
56
- def self.nodes_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, []))
57
- context.each { |node| nodes_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet)
91
+ # @return [String, Hash]
92
+ # rubocop:disable Metrics
93
+ def value
94
+ @value ||=
95
+ if item_node?
96
+ hash = item.to_h
58
97
 
59
- if context.is_a?(Nokogiri::XML::Element) && !Document.ignore_node?(context)
60
- node_set << context if property_node?(context)
98
+ return hash.merge(parser.value) if embedded_markup_property?
61
99
 
62
- nodes_from(context.element_children, node_set) unless Item.item_node?(context)
63
- end
100
+ p_property = item.properties.find { |property| property.name == 'name' } if plain_text_property?
101
+ u_property = item.properties.find { |property| property.name == 'url' } if url_property?
64
102
 
65
- node_set
66
- end
67
-
68
- # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
69
- # @return [Array<MicroMicro::Property>]
70
- def self.properties_from(context)
71
- nodes_from(context).map do |node|
72
- types_from(node).map { |prefix, name| new(node, name: name, prefix: prefix) }
73
- end.flatten
103
+ hash.merge(value: (p_property || u_property || parser).value)
104
+ else
105
+ parser.value
106
+ end
74
107
  end
108
+ # rubocop:enable Metrics
75
109
 
76
- # @param node [Nokogiri::XML::Element]
77
110
  # @return [Boolean]
78
- def self.property_node?(node)
79
- types_from(node).any?
80
- end
81
-
82
- # @param node [Nokogiri::XML::Element]
83
- # @return [Array<Array(String, String)>]
84
- #
85
- # @example
86
- # node = Nokogiri::HTML('<a href="https://sixtwothree.org" class="p-name u-url">Jason Garber</a>').at_css('a')
87
- # MicroMicro::Property.types_from(node) #=> [['p', 'name'], ['u', 'url']]
88
- def self.types_from(node)
89
- node.classes.select { |token| token.match?(/^(?:dt|e|p|u)(?:\-[0-9a-z]+)?(?:\-[a-z]+)+$/) }.map { |token| token.split(/\-/, 2) }.uniq
111
+ def value?
112
+ value.present?
90
113
  end
91
114
 
92
115
  private
93
116
 
94
- # @return [MicroMicro::Item, nil]
95
- def item
96
- @item ||= Item.new(node) if item_node?
97
- end
98
-
99
- # @reutrn [String, nil]
100
- def item_value
101
- return unless item_node?
102
-
103
- obj_by_prefix = case prefix
104
- when 'e' then item
105
- when 'p' then item.properties.find { |property| property.name == 'name' }
106
- when 'u' then item.properties.find { |property| property.name == 'url' }
107
- end
108
-
109
- (obj_by_prefix || parser).value
110
- end
111
-
112
117
  def parser
113
118
  @parser ||= PROPERTY_PARSERS_MAP[prefix].new(self)
114
119
  end