micromicro 1.1.0 → 3.0.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 +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
|
[![Gem](https://img.shields.io/gem/v/micromicro.svg?logo=rubygems&style=for-the-badge)](https://rubygems.org/gems/micromicro)
|
6
6
|
[![Downloads](https://img.shields.io/gem/dt/micromicro.svg?logo=rubygems&style=for-the-badge)](https://rubygems.org/gems/micromicro)
|
7
|
-
[![Build](https://img.shields.io/
|
7
|
+
[![Build](https://img.shields.io/github/workflow/status/jgarber623/micromicro/CI?logo=github&style=for-the-badge)](https://github.com/jgarber623/micromicro/actions/workflows/ci.yml)
|
8
8
|
[![Maintainability](https://img.shields.io/codeclimate/maintainability/jgarber623/micromicro.svg?logo=code-climate&style=for-the-badge)](https://codeclimate.com/github/jgarber623/micromicro)
|
9
9
|
[![Coverage](https://img.shields.io/codeclimate/c/jgarber623/micromicro.svg?logo=code-climate&style=for-the-badge)](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
|