micromicro 1.1.0 → 3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -1
- data/CONTRIBUTING.md +3 -3
- data/README.md +9 -102
- data/lib/micro_micro/collectible.rb +2 -0
- data/lib/micro_micro/collections/base_collection.rb +8 -1
- data/lib/micro_micro/collections/items_collection.rb +84 -1
- data/lib/micro_micro/collections/properties_collection.rb +111 -0
- data/lib/micro_micro/collections/relationships_collection.rb +85 -6
- data/lib/micro_micro/document.rb +21 -103
- data/lib/micro_micro/helpers.rb +94 -0
- data/lib/micro_micro/implied_property.rb +15 -0
- data/lib/micro_micro/item.rb +93 -79
- data/lib/micro_micro/parsers/base_implied_property_parser.rb +29 -0
- data/lib/micro_micro/parsers/base_property_parser.rb +6 -12
- data/lib/micro_micro/parsers/date_time_parser.rb +61 -25
- data/lib/micro_micro/parsers/date_time_property_parser.rb +10 -6
- data/lib/micro_micro/parsers/embedded_markup_property_parser.rb +4 -2
- data/lib/micro_micro/parsers/implied_name_property_parser.rb +15 -16
- data/lib/micro_micro/parsers/implied_photo_property_parser.rb +21 -43
- data/lib/micro_micro/parsers/implied_url_property_parser.rb +12 -30
- data/lib/micro_micro/parsers/plain_text_property_parser.rb +4 -1
- data/lib/micro_micro/parsers/url_property_parser.rb +22 -12
- data/lib/micro_micro/parsers/value_class_pattern_parser.rb +29 -42
- data/lib/micro_micro/property.rb +126 -56
- data/lib/micro_micro/relationship.rb +38 -13
- data/lib/micro_micro/version.rb +3 -1
- data/lib/micromicro.rb +32 -26
- data/micromicro.gemspec +11 -6
- metadata +22 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6734c4d9cbd071d3288a5f8c72de07095fc6db2915224f97684a0577362bcdb0
|
4
|
+
data.tar.gz: 9225043ef91161f2a92fa338bc874771dc55d9e81ffe969fe7b005c9dbc28403
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58824c1699a2aff5e22d906cbb449f95f55a665d7374ba62e26ddfa3fd6986ae952e22965446e4bbe973d2e17a1f05cba32e74f7d30e1e327fbc262ebce7b1f1
|
7
|
+
data.tar.gz: aa9db8c15e10ecc08fa65db0cf6964914681ef72b552a300c4b95899b4a837835c1c69baff9b8e48586df34eefb7bb4156e55a5c81582deda4a9948554224f48
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,52 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v3.0.0 / 2022-08-28
|
4
|
+
|
5
|
+
- Improved YARD documentation
|
6
|
+
- New `Item` instance methods (8105d6f):
|
7
|
+
- `MicroMicro::Item#children?`
|
8
|
+
- `MicroMicro::Item#id?`
|
9
|
+
- **Breaking change:** Remove property-centric methods from `MicroMicro::Item` (926dedb):
|
10
|
+
- `MicroMicro::Item#plain_text_properties`
|
11
|
+
- `MicroMicro::Item#url_properties`
|
12
|
+
- Add predicate methods to `MicroMicro::Collections::PropertiesCollection` (82e91c8):
|
13
|
+
- `MicroMicro::Collections::PropertiesCollection#plain_text_properties?`
|
14
|
+
- `MicroMicro::Collections::PropertiesCollection#url_properties?`
|
15
|
+
- Add collections search methods `#where` and `#find_by` (847cb77)
|
16
|
+
- **Breaking change:** Refactor `.node_set_from` class methods into private classes (b18a714)
|
17
|
+
|
18
|
+
## 2.0.1 / 2022-08-20
|
19
|
+
|
20
|
+
- Use ruby/debug instead of pry-byebug (2965b2e)
|
21
|
+
- Update nokogiri-html-ext to v0.2.2 (921c486)
|
22
|
+
- Include root items with property class names (dd14212)
|
23
|
+
|
24
|
+
## 2.0.0 / 2022-08-12
|
25
|
+
|
26
|
+
- Refactor implied property parsers (203fec9)
|
27
|
+
- Add `Helpers` module (caa1c02)
|
28
|
+
- New `PropertiesCollection` and `Property` instance methods (e9bb38b):
|
29
|
+
- `PropertiesCollection#plain_text_properties`
|
30
|
+
- `PropertiesCollection#url_properties`
|
31
|
+
- `Property#date_time_property?`
|
32
|
+
- `Property#embedded_markup_property?`
|
33
|
+
- `Property#plain_text_property?`
|
34
|
+
- `Property#url_property?`
|
35
|
+
- Remove Addressable (66c2bb4)
|
36
|
+
- Refactor classes to use nokogiri-html-ext (33fdf4a)
|
37
|
+
- Update activesupport (563bf56)
|
38
|
+
- **Breaking change:** Set minimum supported Ruby to 2.7 (ba17d05)
|
39
|
+
- Update development Ruby to 2.7.6 (ba17d05)
|
40
|
+
- Remove Reek (c1e76c5)
|
41
|
+
- Update runtime dependency version constraints (f83f26a)
|
42
|
+
- ~~**Breaking change:** Set minimum supported Ruby to 2.6~~ (fc588cd)
|
43
|
+
- ~~Update development Ruby to 2.6.10~~ (d05a2ac)
|
44
|
+
|
3
45
|
## 1.1.0 / 2021-06-10
|
4
46
|
|
5
47
|
- Replace Absolutely dependency with Addressable (e93721b)
|
6
48
|
- Add support for Ruby 3.0 (d897c54)
|
7
|
-
- Update development Ruby version to 2.
|
49
|
+
- Update development Ruby version to 2.6.10 (051c9ad)
|
8
50
|
|
9
51
|
## 1.0.0 / 2020-11-08
|
10
52
|
|
data/CONTRIBUTING.md
CHANGED
@@ -8,9 +8,9 @@ There are a couple ways you can help improve MicroMicro:
|
|
8
8
|
|
9
9
|
## Getting Started
|
10
10
|
|
11
|
-
MicroMicro is developed using Ruby 2.
|
11
|
+
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).
|
12
12
|
|
13
|
-
Before making changes to MicroMicro, you'll want to install Ruby 2.
|
13
|
+
Before making changes to MicroMicro, you'll want to install Ruby 2.7.6. 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). Once you've installed Ruby 2.7.6 using your method of choice, install the project's gems by running:
|
14
14
|
|
15
15
|
```sh
|
16
16
|
bundle install
|
@@ -22,7 +22,7 @@ bundle install
|
|
22
22
|
1. Install development dependencies as outlined above.
|
23
23
|
1. Create a feature branch for the code changes you're looking to make: `git checkout -b my-new-feature`.
|
24
24
|
1. _Write some code!_
|
25
|
-
1. If your changes would benefit from testing, add the necessary tests and verify everything passes by running `
|
25
|
+
1. If your changes would benefit from testing, add the necessary tests and verify everything passes by running `bundle exec rspec`.
|
26
26
|
1. Commit your changes: `git commit -am 'Add some new feature or fix some issue'`. _(See [this excellent article](https://chris.beams.io/posts/git-commit/) for tips on writing useful Git commit messages.)_
|
27
27
|
1. Push the branch to your fork: `git push -u origin my-new-feature`.
|
28
28
|
1. Create a new [pull request][pulls] and we'll review your changes.
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
[](https://rubygems.org/gems/micromicro)
|
6
6
|
[](https://rubygems.org/gems/micromicro)
|
7
|
-
[](https://github.com/jgarber623/micromicro/actions/workflows/ci.yml)
|
8
8
|
[](https://codeclimate.com/github/jgarber623/micromicro)
|
9
9
|
[](https://codeclimate.com/github/jgarber623/micromicro/code)
|
10
10
|
|
@@ -12,43 +12,31 @@
|
|
12
12
|
|
13
13
|
- Parses microformats2-encoded HTML documents according to the [microformats2 parsing specification](https://microformats.org/wiki/microformats2-parsing)
|
14
14
|
- Passes all microformats2 tests from [the official test suite](https://github.com/microformats/tests)¹
|
15
|
-
- Supports Ruby 2.
|
15
|
+
- Supports Ruby 2.7 and newer
|
16
16
|
|
17
17
|
**Note:** MicroMicro **does not** parse [Classic Microformats](https://microformats.org/wiki/Main_Page#Classic_Microformats) (referred to in [the parsing specification](https://microformats.org/wiki/microformats2-parsing#note_backward_compatibility_details) as "backcompat root classes" and "backcompat properties" and in vocabulary specifications in the "Parser Compatibility" sections [e.g. [h-entry](https://microformats.org/wiki/h-entry#Parser_Compatibility)]). To parse documents marked up with Classic Microformats, consider using [the official microformats-ruby parser](https://github.com/microformats/microformats-ruby).
|
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.5 (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.5.9 and is additionally tested against Ruby 2.6, 2.7, and 3.0 using [CircleCI](https://app.circleci.com/pipelines/github/jgarber623/micromicro).
|
26
|
-
|
27
21
|
## Installation
|
28
22
|
|
29
|
-
If you're using [Bundler](https://bundler.io), add MicroMicro to your project's
|
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
|
-
source 'https://rubygems.org'
|
33
|
-
|
34
26
|
gem 'micromicro'
|
35
27
|
```
|
36
28
|
|
37
|
-
…and
|
29
|
+
…and run `bundle install` in your shell.
|
30
|
+
|
31
|
+
To install the gem manually, run the following in your shell:
|
38
32
|
|
39
33
|
```sh
|
40
|
-
|
34
|
+
gem install micromicro
|
41
35
|
```
|
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.
|
145
52
|
|
146
53
|
## Contributing
|
147
54
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MicroMicro
|
2
4
|
module Collections
|
3
5
|
class BaseCollection
|
@@ -13,9 +15,14 @@ module MicroMicro
|
|
13
15
|
end
|
14
16
|
|
15
17
|
# @return [String]
|
18
|
+
#
|
19
|
+
# :nocov:
|
16
20
|
def inspect
|
17
|
-
|
21
|
+
"#<#{self.class}:#{format('%#0x', object_id)} " \
|
22
|
+
"count: #{count}, " \
|
23
|
+
"members: #{members.inspect}>"
|
18
24
|
end
|
25
|
+
# :nocov:
|
19
26
|
|
20
27
|
# @param member [MicroMicro::Item, MicroMicro::Property, MicroMicro::Relationship]
|
21
28
|
def push(member)
|
@@ -1,14 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MicroMicro
|
2
4
|
module Collections
|
3
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
|
+
#
|
4
50
|
# @return [Array<Hash{Symbol => Array<String, Hash>}>]
|
5
51
|
def to_a
|
6
52
|
map(&:to_h)
|
7
53
|
end
|
8
54
|
|
55
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Item} types.
|
56
|
+
#
|
57
|
+
# @see MicroMicro::Item#types
|
58
|
+
#
|
9
59
|
# @return [Array<String>]
|
10
60
|
def types
|
11
|
-
@types ||=
|
61
|
+
@types ||= flat_map(&:types).uniq.sort
|
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))
|
12
95
|
end
|
13
96
|
end
|
14
97
|
end
|
@@ -1,20 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MicroMicro
|
2
4
|
module Collections
|
3
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
|
+
#
|
4
38
|
# @return [Array<String>]
|
5
39
|
def names
|
6
40
|
@names ||= map(&:name).uniq.sort
|
7
41
|
end
|
8
42
|
|
43
|
+
# A collection of plain text {MicroMicro::Property}s parsed from the node.
|
44
|
+
#
|
45
|
+
# @see MicroMicro::Property#plain_text_property?
|
46
|
+
#
|
47
|
+
# @return [MicroMicro::Collections::PropertiesCollection]
|
48
|
+
def plain_text_properties
|
49
|
+
@plain_text_properties ||= self.class.new(select(&:plain_text_property?))
|
50
|
+
end
|
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
|
+
#
|
9
65
|
# @return [Hash{Symbol => Array<String, Hash>}]
|
10
66
|
def to_h
|
11
67
|
group_by(&:name).symbolize_keys.deep_transform_values(&:value)
|
12
68
|
end
|
13
69
|
|
70
|
+
# A collection of url {MicroMicro::Property}s parsed from the node.
|
71
|
+
#
|
72
|
+
# @see MicroMicro::Property#url_property?
|
73
|
+
#
|
74
|
+
# @return [MicroMicro::Collections::PropertiesCollection]
|
75
|
+
def url_properties
|
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?
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return an Array of this collection's unique {MicroMicro::Property}
|
88
|
+
# values.
|
89
|
+
#
|
90
|
+
# @see MicroMicro::Property#value
|
91
|
+
#
|
14
92
|
# @return [Array<String, Hash>]
|
15
93
|
def values
|
16
94
|
@values ||= map(&:value).uniq
|
17
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
|
18
129
|
end
|
19
130
|
end
|
20
131
|
end
|
@@ -1,32 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MicroMicro
|
2
4
|
module Collections
|
3
5
|
class RelationshipsCollection < BaseCollection
|
4
|
-
|
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.
|
5
23
|
#
|
6
|
-
# @
|
7
|
-
|
8
|
-
|
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
|
9
31
|
end
|
10
32
|
|
33
|
+
# Return a Hash of this collection's {MicroMicro::Relationship}s grouped
|
34
|
+
# by their +rel+ attribute value.
|
35
|
+
#
|
11
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
|
12
38
|
#
|
13
39
|
# @return [Hash{Symbol => Array<String>}]
|
14
40
|
def group_by_rel
|
15
|
-
# flat_map { |member| member.rels.map { |rel| [rel, member.href] } }.group_by(&:shift).symbolize_keys.transform_values(&:flatten).transform_values(&:uniq)
|
16
41
|
each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |member, hash|
|
17
42
|
member.rels.each { |rel| hash[rel] << member.href }
|
18
43
|
end.symbolize_keys.transform_values(&:uniq)
|
19
44
|
end
|
20
45
|
|
46
|
+
# Return a Hash of this collection's {MicroMicro::Relationship}s grouped
|
47
|
+
# by their +href+ attribute value.
|
48
|
+
#
|
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
|
51
|
+
#
|
52
|
+
# @return [Hash{Symbol => Hash{Symbol => Array, String}}]
|
53
|
+
def group_by_url
|
54
|
+
group_by(&:href).symbolize_keys.transform_values { |relationships| relationships.first.to_h.slice!(:href) }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Relationship}
|
58
|
+
# +rel+ attrivute values.
|
59
|
+
#
|
60
|
+
# @see MicroMicro::Relationship#rels
|
61
|
+
#
|
21
62
|
# @return [Array<String>]
|
22
63
|
def rels
|
23
|
-
@rels ||=
|
64
|
+
@rels ||= flat_map(&:rels).uniq.sort
|
24
65
|
end
|
25
66
|
|
67
|
+
# Retrieve an Array of this collection's unique {MicroMicro::Relationship}
|
68
|
+
# +href+ attribute values.
|
69
|
+
#
|
70
|
+
# @see MicroMicro::Relationship#urls
|
71
|
+
#
|
26
72
|
# @return [Array<String>]
|
27
73
|
def urls
|
28
74
|
@urls ||= map(&:href).uniq.sort
|
29
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
|
30
109
|
end
|
31
110
|
end
|
32
111
|
end
|