micromicro 2.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +3 -96
- data/lib/micro_micro/collections/base_collection.rb +2 -1
- data/lib/micro_micro/collections/items_collection.rb +81 -0
- data/lib/micro_micro/collections/properties_collection.rb +102 -3
- data/lib/micro_micro/collections/relationships_collection.rb +82 -4
- data/lib/micro_micro/document.rb +12 -6
- data/lib/micro_micro/helpers.rb +6 -0
- data/lib/micro_micro/implied_property.rb +13 -0
- data/lib/micro_micro/item.rb +65 -46
- data/lib/micro_micro/parsers/base_property_parser.rb +2 -0
- data/lib/micro_micro/parsers/date_time_parser.rb +3 -5
- data/lib/micro_micro/parsers/date_time_property_parser.rb +3 -0
- data/lib/micro_micro/parsers/embedded_markup_property_parser.rb +1 -0
- data/lib/micro_micro/parsers/image_element_parser.rb +68 -0
- data/lib/micro_micro/parsers/implied_name_property_parser.rb +1 -0
- data/lib/micro_micro/parsers/implied_photo_property_parser.rb +7 -6
- data/lib/micro_micro/parsers/implied_url_property_parser.rb +1 -0
- data/lib/micro_micro/parsers/plain_text_property_parser.rb +1 -0
- data/lib/micro_micro/parsers/url_property_parser.rb +4 -5
- data/lib/micro_micro/parsers/value_class_pattern_parser.rb +4 -2
- data/lib/micro_micro/property.rb +78 -20
- data/lib/micro_micro/relationship.rb +26 -3
- data/lib/micro_micro/version.rb +1 -1
- data/lib/micromicro.rb +8 -6
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75bb9eaa673828648bc3f0a78d9822f434ae99317ae9499998f984c661c0771b
|
4
|
+
data.tar.gz: 2ab7a2896a8498507cb57f7e1c5a10c1e5dff8091328370a10e645420374ec12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a24f38005e975861d4e5ce1c3b728ea4535d7a094cae2515a8b6e7f0e7bb7abe7558eec44651a7e833d0120d397bcb45687022c374a039f5d755d46798264e8c
|
7
|
+
data.tar.gz: 58f27f493e1255ef7b4ea1904cb643c1392f62dacea645708142f153eccfba2ed0a9ed52e33f76f4ec4eae5012b9dce159ec963c216a5506969b4a47be4e2042
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 3.1.0 / 2022-09-24
|
4
|
+
|
5
|
+
- **New feature:** parse `img[srcset]` (microformats/microformats2-parsing#7) (cdda328)
|
6
|
+
- Improve usage of activesupport extensions (5ed120c)
|
7
|
+
|
8
|
+
## 3.0.0 / 2022-08-28
|
9
|
+
|
10
|
+
- Improved YARD documentation
|
11
|
+
- New `Item` instance methods (8105d6f):
|
12
|
+
- `MicroMicro::Item#children?`
|
13
|
+
- `MicroMicro::Item#id?`
|
14
|
+
- **Breaking change:** Remove property-centric methods from `MicroMicro::Item` (926dedb):
|
15
|
+
- `MicroMicro::Item#plain_text_properties`
|
16
|
+
- `MicroMicro::Item#url_properties`
|
17
|
+
- Add predicate methods to `MicroMicro::Collections::PropertiesCollection` (82e91c8):
|
18
|
+
- `MicroMicro::Collections::PropertiesCollection#plain_text_properties?`
|
19
|
+
- `MicroMicro::Collections::PropertiesCollection#url_properties?`
|
20
|
+
- Add collections search methods `#where` and `#find_by` (847cb77)
|
21
|
+
- **Breaking change:** Refactor `.node_set_from` class methods into private classes (b18a714)
|
22
|
+
|
3
23
|
## 2.0.1 / 2022-08-20
|
4
24
|
|
5
25
|
- Use ruby/debug instead of pry-byebug (2965b2e)
|
data/README.md
CHANGED
@@ -18,15 +18,9 @@
|
|
18
18
|
|
19
19
|
<small>¹ …with some exceptions until [this pull request](https://github.com/microformats/tests/pull/112) is merged.</small>
|
20
20
|
|
21
|
-
## Getting Started
|
22
|
-
|
23
|
-
Before installing and using MicroMicro, you'll want to have [Ruby](https://www.ruby-lang.org) 2.7 (or newer) installed. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm).
|
24
|
-
|
25
|
-
MicroMicro is developed using Ruby 2.7.6 and is additionally tested against Ruby 3.0 and 3.1 using [GitHub Actions](https://github.com/jgarber623/micromicro/actions).
|
26
|
-
|
27
21
|
## Installation
|
28
22
|
|
29
|
-
If you're using [Bundler](https://bundler.io) to manage gem dependencies, add MicroMicro to your project's Gemfile:
|
23
|
+
Before installing and using MicroMicro, you'll want to have [Ruby](https://www.ruby-lang.org) 2.7 (or newer) installed. If you're using [Bundler](https://bundler.io) to manage gem dependencies, add MicroMicro to your project's Gemfile:
|
30
24
|
|
31
25
|
```ruby
|
32
26
|
gem 'micromicro'
|
@@ -42,13 +36,7 @@ gem install micromicro
|
|
42
36
|
|
43
37
|
## Usage
|
44
38
|
|
45
|
-
|
46
|
-
|
47
|
-
MicroMicro's `parse` method accepts two arguments: a `String` of markup and a `String` representing the URL associated with that markup.
|
48
|
-
|
49
|
-
The markup (typically HTML) can be retrieved from the Web using a library of your choosing or provided inline as a simple `String` (e.g. `<div class="h-card">Jason Garber</div>`) The URL provided is used to resolve relative URLs in accordance with the document's language rules.
|
50
|
-
|
51
|
-
An example using a simple `String` of HTML as input:
|
39
|
+
MicroMicro's `parse` method accepts two arguments: a `String` of markup and a `String` representing the URL associated with that markup. The resulting `MicroMicro::Document` may be converted to a `Hash` which may be further manipulated using conventional Ruby tooling.
|
52
40
|
|
53
41
|
```ruby
|
54
42
|
require 'micromicro'
|
@@ -60,88 +48,7 @@ doc.to_h
|
|
60
48
|
#=> { :items => [{ :type => ["h-card"], :properties => { :name => ["Jason Garber"] } }], :rels => {}, :"rel-urls" => {} }
|
61
49
|
```
|
62
50
|
|
63
|
-
|
64
|
-
|
65
|
-
Another example pulling the source HTML from [Tantek](https://tantek.com)'s website:
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
require 'net/http'
|
69
|
-
require 'micromicro'
|
70
|
-
|
71
|
-
url = 'https://tantek.com'
|
72
|
-
rsp = Net::HTTP.get(URI.parse(url))
|
73
|
-
|
74
|
-
doc = MicroMicro.parse(rsp, url)
|
75
|
-
#=> #<MicroMicro::Document items: #<MicroMicro::Collections::ItemsCollection count: 1, members: […]>, relationships: #<MicroMicro::Collections::RelationshipsCollection count: 31, members: […]>>
|
76
|
-
|
77
|
-
doc.to_h
|
78
|
-
#=> { :items => [{ :type => ["h-card"], :properties => {…}, :children => […]}], :rels => {…}, :'rel-urls' => {…} }
|
79
|
-
```
|
80
|
-
|
81
|
-
### Advanced Usage
|
82
|
-
|
83
|
-
Building on the example above, a MicroMicro-parsed document is navigable and manipulable using a familiar `Enumerable`-esque interface.
|
84
|
-
|
85
|
-
#### Items
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
doc.items.first
|
89
|
-
#=> #<MicroMicro::Item types: ["h-card"], properties: 42, children: 6>
|
90
|
-
|
91
|
-
# 🆕 in v1.0.0
|
92
|
-
doc.items.types
|
93
|
-
#=> ["h-card"]
|
94
|
-
|
95
|
-
doc.items.first.children
|
96
|
-
#=> #<MicroMicro::Collections::ItemsCollection count: 6, members: […]>
|
97
|
-
```
|
98
|
-
|
99
|
-
#### Properties
|
100
|
-
|
101
|
-
```ruby
|
102
|
-
doc.items.first.properties
|
103
|
-
#=> #<MicroMicro::Collections::PropertiesCollection count: 42, members: […]>
|
104
|
-
|
105
|
-
# 🆕 in v1.0.0
|
106
|
-
doc.items.first.plain_text_properties
|
107
|
-
#=> #<MicroMicro::Collections::PropertiesCollection count: 34, members: […]>
|
108
|
-
|
109
|
-
# 🆕 in v1.0.0
|
110
|
-
doc.items.first.url_properties
|
111
|
-
#=> #<MicroMicro::Collections::PropertiesCollection count: 11, members: […]>
|
112
|
-
|
113
|
-
# 🆕 in v1.0.0
|
114
|
-
doc.items.first.properties.names
|
115
|
-
#=> ["category", "name", "note", "org", "photo", "pronoun", "pronouns", "role", "uid", "url"]
|
116
|
-
|
117
|
-
# 🆕 in v1.0.0
|
118
|
-
doc.items.first.properties.values
|
119
|
-
#=> [{:value=>"https://tantek.com/photo.jpg", :alt=>""}, "https://tantek.com/", "Tantek Çelik", "Inventor, writer, teacher, runner, coder, more.", "Inventor", "writer", "teacher", "runner", "coder", …]
|
120
|
-
|
121
|
-
doc.items.first.properties[7]
|
122
|
-
#=> #<MicroMicro::Property name: "category", prefix: "p", value: "teacher">
|
123
|
-
|
124
|
-
doc.items.first.properties.take(5).map { |property| [property.name, property.value] }
|
125
|
-
#=> [["photo", { :value => "https://tantek.com/photo.jpg", :alt => "" }], ["url", "https://tantek.com/"], ["uid", "https://tantek.com/"], ["name", "Tantek Çelik"], ["role", "Inventor, writer, teacher, runner, coder, more."]]
|
126
|
-
```
|
127
|
-
|
128
|
-
#### Relationships
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
doc.relationships.first
|
132
|
-
#=> #<MicroMicro::Relationship href: "https://tantek.com/", rels: ["canonical"]>
|
133
|
-
|
134
|
-
# 🆕 in v1.0.0
|
135
|
-
doc.relationships.rels
|
136
|
-
#=> ["alternate", "apple-touch-icon-precomposed", "author", "authorization_endpoint", "bookmark", "canonical", "hub", "icon", "me", "microsub", …]
|
137
|
-
|
138
|
-
# 🆕 in v1.0.0
|
139
|
-
doc.relationships.urls
|
140
|
-
#=> ["http://dribbble.com/tantek/", "http://last.fm/user/tantekc", "https://aperture.p3k.io/microsub/277", "https://en.wikipedia.org/wiki/User:Tantek", "https://github.com/tantek", "https://indieauth.com/auth", "https://indieauth.com/openid", "https://micro.blog/t", "https://pubsubhubbub.superfeedr.com/", "https://tantek.com/", …]
|
141
|
-
|
142
|
-
doc.relationships.find { |relationship| relationship.rels.include?('webmention') }
|
143
|
-
# => #<MicroMicro::Relationship href: "https://webmention.io/tantek.com/webmention", rels: ["webmention"]>
|
144
|
-
```
|
51
|
+
See [USAGE.md](https://github.com/jgarber623/micromicro/blob/main/USAGE.md) for detailed examples of MicroMicro's features. Additional structured documentation is available on [RubyDoc.info](https://rubydoc.info/gems/micromicro).
|
145
52
|
|
146
53
|
## Contributing
|
147
54
|
|
@@ -3,15 +3,96 @@
|
|
3
3
|
module MicroMicro
|
4
4
|
module Collections
|
5
5
|
class ItemsCollection < BaseCollection
|
6
|
+
class ItemsCollectionSearch
|
7
|
+
attr_reader :results
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@results = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def search(items, **args, &block)
|
14
|
+
items.each do |item|
|
15
|
+
results << item if item_matches_conditions?(item, **args, &block)
|
16
|
+
|
17
|
+
search(item.properties.filter_map { |property| property.item if property.item_node? }, **args, &block)
|
18
|
+
search(item.children, **args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
results
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def item_matches_conditions?(item, **args)
|
27
|
+
return yield(item) if args.none?
|
28
|
+
|
29
|
+
args.all? { |key, value| (Array(item.public_send(key.to_sym)) & Array(value)).any? }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private_constant :ItemsCollectionSearch
|
34
|
+
|
35
|
+
# Return the first {MicroMicro::Item} from a search.
|
36
|
+
#
|
37
|
+
# @see #where
|
38
|
+
#
|
39
|
+
# @param (see #where)
|
40
|
+
# @yieldparam (see #where))
|
41
|
+
# @return [MicroMicro::Item, nil]
|
42
|
+
def find_by(**args, &block)
|
43
|
+
where(**args, &block).first
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return an Array of this collection's {MicroMicro::Item}s as Hashes.
|
47
|
+
#
|
48
|
+
# @see MicroMicro::Item#to_h
|
49
|
+
#
|
6
50
|
# @return [Array<Hash{Symbol => Array<String, Hash>}>]
|
7
51
|
def to_a
|
8
52
|
map(&:to_h)
|
9
53
|
end
|
10
54
|
|
55
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Item} types.
|
56
|
+
#
|
57
|
+
# @see MicroMicro::Item#types
|
58
|
+
#
|
11
59
|
# @return [Array<String>]
|
12
60
|
def types
|
13
61
|
@types ||= flat_map(&:types).uniq.sort
|
14
62
|
end
|
63
|
+
|
64
|
+
# Recursively search this collection for {MicroMicro::Item}s matching the
|
65
|
+
# given conditions.
|
66
|
+
#
|
67
|
+
# If a Hash is supplied, the returned collection will include
|
68
|
+
# {MicroMicro::Item}s matching _all_ conditions. Keys must be Symbols
|
69
|
+
# matching an instance method on {MicroMicro::Item} and values may be
|
70
|
+
# either a String or an Array of Strings.
|
71
|
+
#
|
72
|
+
# @example Search using a Hash with a String value
|
73
|
+
# MicroMicro.parse(markup, url).items.where(types: 'h-card')
|
74
|
+
#
|
75
|
+
# @example Search using a Hash with an Array value
|
76
|
+
# MicroMicro.parse(markup, url).items.where(types: ['h-card', 'h-entry'])
|
77
|
+
#
|
78
|
+
# When passing a block, each {MicroMicro::Item} in this collection is
|
79
|
+
# yielded to the block and the returned collection will include
|
80
|
+
# {MicroMicro::Item}s that cause the block to return a value other than
|
81
|
+
# +false+ or +nil+.
|
82
|
+
#
|
83
|
+
# @example Search using a block
|
84
|
+
# MicroMicro.parse(markup, url).items.where do |item|
|
85
|
+
# item.properties.names.include?('email')
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# @param args [Hash{Symbol => String, Array<String>}]
|
89
|
+
# @yieldparam item [MicroMicro::Item]
|
90
|
+
# @return [MicroMicro::Collections::ItemsCollection]
|
91
|
+
def where(**args, &block)
|
92
|
+
return self if args.none? && !block
|
93
|
+
|
94
|
+
self.class.new(ItemsCollectionSearch.new.search(self, **args, &block))
|
95
|
+
end
|
15
96
|
end
|
16
97
|
end
|
17
98
|
end
|
@@ -3,30 +3,129 @@
|
|
3
3
|
module MicroMicro
|
4
4
|
module Collections
|
5
5
|
class PropertiesCollection < BaseCollection
|
6
|
+
class PropertiesCollectionSearch
|
7
|
+
def search(properties, **args, &block)
|
8
|
+
properties.select { |property| property_matches_conditions?(property, **args, &block) }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def property_matches_conditions?(property, **args)
|
14
|
+
return yield(property) if args.none?
|
15
|
+
|
16
|
+
args.all? { |key, value| (Array(property.public_send(key.to_sym)) & Array(value)).any? }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private_constant :PropertiesCollectionSearch
|
21
|
+
|
22
|
+
# Return the first {MicroMicro::Property} from a search.
|
23
|
+
#
|
24
|
+
# @see #where
|
25
|
+
#
|
26
|
+
# @param (see #where)
|
27
|
+
# @yieldparam (see #where))
|
28
|
+
# @return [MicroMicro::Property, nil]
|
29
|
+
def find_by(**args, &block)
|
30
|
+
where(**args, &block).first
|
31
|
+
end
|
32
|
+
|
33
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Property}
|
34
|
+
# names.
|
35
|
+
#
|
36
|
+
# @see MicroMicro::Property#name
|
37
|
+
#
|
6
38
|
# @return [Array<String>]
|
7
39
|
def names
|
8
40
|
@names ||= map(&:name).uniq.sort
|
9
41
|
end
|
10
42
|
|
43
|
+
# A collection of plain text {MicroMicro::Property}s parsed from the node.
|
44
|
+
#
|
45
|
+
# @see MicroMicro::Property#plain_text_property?
|
46
|
+
#
|
11
47
|
# @return [MicroMicro::Collections::PropertiesCollection]
|
12
48
|
def plain_text_properties
|
13
|
-
self.class.new(select(&:plain_text_property?))
|
49
|
+
@plain_text_properties ||= self.class.new(select(&:plain_text_property?))
|
14
50
|
end
|
15
51
|
|
52
|
+
# Does this {MicroMicro::Collections::PropertiesCollection} include any
|
53
|
+
# plain text {MicroMicro::Property}s?
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
def plain_text_properties?
|
57
|
+
plain_text_properties.any?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a Hash of this collection's {MicroMicro::Property}s as Arrays.
|
61
|
+
#
|
62
|
+
# @see MicroMicro::Property#name
|
63
|
+
# @see MicroMicro::Property#value
|
64
|
+
#
|
16
65
|
# @return [Hash{Symbol => Array<String, Hash>}]
|
17
66
|
def to_h
|
18
|
-
group_by(&:name).
|
67
|
+
group_by(&:name).transform_keys(&:to_sym).deep_transform_values(&:value)
|
19
68
|
end
|
20
69
|
|
70
|
+
# A collection of url {MicroMicro::Property}s parsed from the node.
|
71
|
+
#
|
72
|
+
# @see MicroMicro::Property#url_property?
|
73
|
+
#
|
21
74
|
# @return [MicroMicro::Collections::PropertiesCollection]
|
22
75
|
def url_properties
|
23
|
-
self.class.new(select(&:url_property?))
|
76
|
+
@url_properties ||= self.class.new(select(&:url_property?))
|
77
|
+
end
|
78
|
+
|
79
|
+
# Does this {MicroMicro::Collections::PropertiesCollection} include any
|
80
|
+
# url {MicroMicro::Property}s?
|
81
|
+
#
|
82
|
+
# @return [Boolean]
|
83
|
+
def url_properties?
|
84
|
+
url_properties.any?
|
24
85
|
end
|
25
86
|
|
87
|
+
# Return an Array of this collection's unique {MicroMicro::Property}
|
88
|
+
# values.
|
89
|
+
#
|
90
|
+
# @see MicroMicro::Property#value
|
91
|
+
#
|
26
92
|
# @return [Array<String, Hash>]
|
27
93
|
def values
|
28
94
|
@values ||= map(&:value).uniq
|
29
95
|
end
|
96
|
+
|
97
|
+
# Search this collection for {MicroMicro::Property}s matching the given
|
98
|
+
# conditions.
|
99
|
+
#
|
100
|
+
# If a Hash is supplied, the returned collection will include
|
101
|
+
# {MicroMicro::Property}s matching _all_ conditions. Keys must be Symbols
|
102
|
+
# matching an instance method on {MicroMicro::Property} and values may be
|
103
|
+
# either a String or an Array of Strings.
|
104
|
+
#
|
105
|
+
# @example Search using a Hash with a String value
|
106
|
+
# MicroMicro.parse(markup, url).properties.where(name: 'url')
|
107
|
+
#
|
108
|
+
# @example Search using a Hash with an Array value
|
109
|
+
# MicroMicro.parse(markup, url).properties.where(name: ['name', 'url'])
|
110
|
+
#
|
111
|
+
# When passing a block, each {MicroMicro::Property} in this collection
|
112
|
+
# is yielded to the block and the returned collection will include
|
113
|
+
# {MicroMicro::Property}s that cause the block to return a value other
|
114
|
+
# than +false+ or +nil+.
|
115
|
+
#
|
116
|
+
# @example Search using a block
|
117
|
+
# MicroMicro.parse(markup, url).properties.where do |property|
|
118
|
+
# property.value.is_a?(Hash)
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# @param args [Hash{Symbol => String, Array<String>}]
|
122
|
+
# @yieldparam property [MicroMicro::Property]
|
123
|
+
# @return [MicroMicro::Collections::PropertiesCollection]
|
124
|
+
def where(**args, &block)
|
125
|
+
return self if args.none? && !block
|
126
|
+
|
127
|
+
self.class.new(PropertiesCollectionSearch.new.search(self, **args, &block))
|
128
|
+
end
|
30
129
|
end
|
31
130
|
end
|
32
131
|
end
|
@@ -3,31 +3,109 @@
|
|
3
3
|
module MicroMicro
|
4
4
|
module Collections
|
5
5
|
class RelationshipsCollection < BaseCollection
|
6
|
+
class RelationshipsCollectionSearch
|
7
|
+
def search(relationships, **args, &block)
|
8
|
+
relationships.select { |relationship| relationship_matches_conditions?(relationship, **args, &block) }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def relationship_matches_conditions?(relationship, **args)
|
14
|
+
return yield(relationship) if args.none?
|
15
|
+
|
16
|
+
args.all? { |key, value| (Array(relationship.public_send(key.to_sym)) & Array(value)).any? }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private_constant :RelationshipsCollectionSearch
|
21
|
+
|
22
|
+
# Return the first {MicroMicro::Relationship} from a search.
|
23
|
+
#
|
24
|
+
# @see #where
|
25
|
+
#
|
26
|
+
# @param (see #where)
|
27
|
+
# @yieldparam (see #where))
|
28
|
+
# @return [MicroMicro::Relationship, nil]
|
29
|
+
def find_by(**args, &block)
|
30
|
+
where(**args, &block).first
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return a Hash of this collection's {MicroMicro::Relationship}s grouped
|
34
|
+
# by their +rel+ attribute value.
|
35
|
+
#
|
6
36
|
# @see https://microformats.org/wiki/microformats2-parsing#parse_a_hyperlink_element_for_rel_microformats
|
37
|
+
# microformats.org: microformats2 parsing specification § Parse a hyperlink element for rel microformats
|
7
38
|
#
|
8
39
|
# @return [Hash{Symbol => Array<String>}]
|
9
40
|
def group_by_rel
|
10
|
-
each_with_object(Hash.new { |hash, key| hash[key] =
|
11
|
-
member.rels.each { |rel| hash[rel] << member.href }
|
12
|
-
end.
|
41
|
+
each_with_object(Hash.new { |hash, key| hash[key] = Set.new }) do |member, hash|
|
42
|
+
member.rels.each { |rel| hash[rel.to_sym] << member.href }
|
43
|
+
end.transform_values(&:to_a)
|
13
44
|
end
|
14
45
|
|
46
|
+
# Return a Hash of this collection's {MicroMicro::Relationship}s grouped
|
47
|
+
# by their +href+ attribute value.
|
48
|
+
#
|
15
49
|
# @see https://microformats.org/wiki/microformats2-parsing#parse_a_hyperlink_element_for_rel_microformats
|
50
|
+
# microformats.org: microformats2 parsing specification § Parse a hyperlink element for rel microformats
|
16
51
|
#
|
17
52
|
# @return [Hash{Symbol => Hash{Symbol => Array, String}}]
|
18
53
|
def group_by_url
|
19
|
-
group_by(&:href).
|
54
|
+
group_by(&:href).to_h { |k, v| [k.to_sym, v.first.to_h.except(:href)] }
|
20
55
|
end
|
21
56
|
|
57
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Relationship}
|
58
|
+
# +rel+ attrivute values.
|
59
|
+
#
|
60
|
+
# @see MicroMicro::Relationship#rels
|
61
|
+
#
|
22
62
|
# @return [Array<String>]
|
23
63
|
def rels
|
24
64
|
@rels ||= flat_map(&:rels).uniq.sort
|
25
65
|
end
|
26
66
|
|
67
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Relationship}
|
68
|
+
# +href+ attribute values.
|
69
|
+
#
|
70
|
+
# @see MicroMicro::Relationship#urls
|
71
|
+
#
|
27
72
|
# @return [Array<String>]
|
28
73
|
def urls
|
29
74
|
@urls ||= map(&:href).uniq.sort
|
30
75
|
end
|
76
|
+
|
77
|
+
# Search this collection for {MicroMicro::Relationship}s matching the
|
78
|
+
# given conditions.
|
79
|
+
#
|
80
|
+
# If a Hash is supplied, the returned collection will include
|
81
|
+
# {MicroMicro::Relationship}s matching _all_ conditions. Keys must be
|
82
|
+
# Symbols matching an instance method on {MicroMicro::Relationship} and
|
83
|
+
# values may be either a String or an Array of Strings.
|
84
|
+
#
|
85
|
+
# @example Search using a Hash with a String value
|
86
|
+
# MicroMicro.parse(markup, url).relationships.where(rels: 'webmention')
|
87
|
+
#
|
88
|
+
# @example Search using a Hash with an Array value
|
89
|
+
# MicroMicro.parse(markup, url).relationships.where(rels: ['me', 'webmention'])
|
90
|
+
#
|
91
|
+
# When passing a block, each {MicroMicro::Relationship} in this collection
|
92
|
+
# is yielded to the block and the returned collection will include
|
93
|
+
# {MicroMicro::Relationship}s that cause the block to return a value other
|
94
|
+
# than +false+ or +nil+.
|
95
|
+
#
|
96
|
+
# @example Search using a block
|
97
|
+
# MicroMicro.parse(markup, url).relationships.where do |relationship|
|
98
|
+
# relationship.href.match?(%r{https://webmention.io/.+})
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# @param args [Hash{Symbol => String, Array<String>}]
|
102
|
+
# @yieldparam relationship [MicroMicro::Relationship]
|
103
|
+
# @return [MicroMicro::Collections::RelationshipsCollection]
|
104
|
+
def where(**args, &block)
|
105
|
+
return self if args.none? && !block
|
106
|
+
|
107
|
+
self.class.new(RelationshipsCollectionSearch.new.search(self, **args, &block))
|
108
|
+
end
|
31
109
|
end
|
32
110
|
end
|
33
111
|
end
|
data/lib/micro_micro/document.rb
CHANGED
@@ -4,10 +4,10 @@ module MicroMicro
|
|
4
4
|
class Document
|
5
5
|
# Parse a string of HTML for microformats2-encoded data.
|
6
6
|
#
|
7
|
+
# @example Parse a String of markup
|
7
8
|
# MicroMicro::Document.new('<a href="/" class="h-card" rel="me">Jason Garber</a>', 'https://sixtwothree.org')
|
8
9
|
#
|
9
|
-
#
|
10
|
-
#
|
10
|
+
# @example Parse a String of markup from a URL
|
11
11
|
# url = 'https://tantek.com'
|
12
12
|
# markup = Net::HTTP.get(URI.parse(url))
|
13
13
|
#
|
@@ -19,8 +19,9 @@ module MicroMicro
|
|
19
19
|
@document = Nokogiri::HTML(markup, base_url).resolve_relative_urls!
|
20
20
|
end
|
21
21
|
|
22
|
-
# :nocov:
|
23
22
|
# @return [String]
|
23
|
+
#
|
24
|
+
# :nocov:
|
24
25
|
def inspect
|
25
26
|
"#<#{self.class}:#{format('%#0x', object_id)} " \
|
26
27
|
"items: #{items.inspect}, " \
|
@@ -28,23 +29,28 @@ module MicroMicro
|
|
28
29
|
end
|
29
30
|
# :nocov:
|
30
31
|
|
31
|
-
# A collection of
|
32
|
+
# A collection of {MicroMicro::Item}s parsed from the provided markup.
|
32
33
|
#
|
33
34
|
# @return [MicroMicro::Collections::ItemsCollection]
|
34
35
|
def items
|
35
36
|
@items ||= Collections::ItemsCollection.new(Item.from_context(document.element_children))
|
36
37
|
end
|
37
38
|
|
38
|
-
# A collection of
|
39
|
+
# A collection of {MicroMicro::Relationship}s parsed from the provided markup.
|
39
40
|
#
|
40
41
|
# @return [MicroMicro::Collections::RelationshipsCollection]
|
41
42
|
def relationships
|
42
|
-
@relationships ||= Collections::RelationshipsCollection.new(Relationship.
|
43
|
+
@relationships ||= Collections::RelationshipsCollection.new(Relationship.from_context(document))
|
43
44
|
end
|
44
45
|
|
45
46
|
# Return the parsed document as a Hash.
|
46
47
|
#
|
47
48
|
# @see https://microformats.org/wiki/microformats2-parsing#parse_a_document_for_microformats
|
49
|
+
# microformats.org: Parse a document for microformats
|
50
|
+
#
|
51
|
+
# @see MicroMicro::Collections::ItemsCollection#to_a
|
52
|
+
# @see MicroMicro::Collections::RelationshipsCollection#group_by_rel
|
53
|
+
# @see MicroMicro::Collections::RelationshipsCollection#group_by_url
|
48
54
|
#
|
49
55
|
# @return [Hash{Symbol => Array, Hash}]
|
50
56
|
def to_h
|
data/lib/micro_micro/helpers.rb
CHANGED
@@ -4,6 +4,8 @@ module MicroMicro
|
|
4
4
|
module Helpers
|
5
5
|
IGNORED_NODE_NAMES = %w[script style template].freeze
|
6
6
|
|
7
|
+
private_constant :IGNORED_NODE_NAMES
|
8
|
+
|
7
9
|
# @param node [Nokogiri::XML::Element]
|
8
10
|
# @param attributes_map [Hash{String => Array}]
|
9
11
|
# @return [String, nil]
|
@@ -56,7 +58,9 @@ module MicroMicro
|
|
56
58
|
end
|
57
59
|
|
58
60
|
# @see https://microformats.org/wiki/microformats2-parsing#parse_an_element_for_properties
|
61
|
+
# microformats.org: microformats2 parsing specification § Parse an element for properties
|
59
62
|
# @see https://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
|
63
|
+
# microformats.org: microformats2 parsing specification § Parsing for implied properties
|
60
64
|
#
|
61
65
|
# @param context [Nokogiri::HTML::Document, Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
|
62
66
|
# @yield [context]
|
@@ -70,6 +74,7 @@ module MicroMicro
|
|
70
74
|
end
|
71
75
|
|
72
76
|
# @see https://microformats.org/wiki/value-class-pattern#Basic_Parsing
|
77
|
+
# microformats.org: Value Class Pattern § Basic Parsing
|
73
78
|
#
|
74
79
|
# @param node [Nokogiri::XML::Element]
|
75
80
|
# @return [Boolean]
|
@@ -78,6 +83,7 @@ module MicroMicro
|
|
78
83
|
end
|
79
84
|
|
80
85
|
# @see https://microformats.org/wiki/value-class-pattern#Parsing_value_from_a_title_attribute
|
86
|
+
# microformats.org: Value Class Pattern § Parsing value from a title attribute
|
81
87
|
#
|
82
88
|
# @param node [Nokogiri::XML::Element]
|
83
89
|
# @return [Boolean]
|
@@ -8,11 +8,24 @@ module MicroMicro
|
|
8
8
|
'url' => Parsers::ImpliedUrlPropertyParser
|
9
9
|
}.freeze
|
10
10
|
|
11
|
+
private_constant :IMPLIED_PROPERTY_PARSERS_MAP
|
12
|
+
|
13
|
+
# Always return +true+ when asked if this {MicroMicro::ImpliedProperty} is
|
14
|
+
# an implied property.
|
15
|
+
#
|
16
|
+
# @see https://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
|
17
|
+
# microformats.org: microformats2 parsing specification § Parsing for implied properties
|
18
|
+
#
|
19
|
+
# @see MicroMicro::Property#implied?
|
20
|
+
#
|
11
21
|
# @return [Boolean]
|
12
22
|
def implied?
|
13
23
|
true
|
14
24
|
end
|
15
25
|
|
26
|
+
# Always return +false+ when asked if this {MicroMicro::ImpliedProperty} is
|
27
|
+
# a {MicroMicro::Item} node.
|
28
|
+
#
|
16
29
|
# @return [Boolean]
|
17
30
|
def item_node?
|
18
31
|
false
|