micromicro 0.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae75d6afb6f7d98bc3a2fc12333ccbd31824e1cecd8336057e551fe6b392a643
4
- data.tar.gz: 877da43669217907635d71015ec574ebc656e8755c8f6267229cebde36f281b0
3
+ metadata.gz: b3037dad18fbd29d5487d985c388e288a8a09beab3f075488696ece006855f64
4
+ data.tar.gz: e0426d2ab7f6bfb762ff856f4bfb3afcca7af1c499ddedefdbfd9111c41c26eb
5
5
  SHA512:
6
- metadata.gz: a4b5a68c2d343fe0935d2103016aacf0b94d7a7c391d3ea360160a25fcb01bc16b7c70ae715e12b17142cedb928bea782b8057db5002df3e9ece2a99fdf1558c
7
- data.tar.gz: 16a62f01b013d56547cebcac3001ecf59b77b3c14653f473a833d66589c6be31b5c53c2e6c547e0ce5c65f3dafb18feeb94be30ae0f57c65a96def024d6afccb
6
+ metadata.gz: 8024a4c6de518aab23991e056554ea97d4a21c06b3ba27e38362840be82b5021bebe618d82698903d1e2ce7a5b49d22b131f8cfb7d460074198a89cef9873476
7
+ data.tar.gz: 6137ab273b1418e2e5f063eda6ef35f1b3bdec5841272e73ef3a9ac25c8e7995ac09aa2495c5f0ad9e88726e88c8fdba97ac50d8d5bdc0e16d271a00c5a42597
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0 / 2022-08-12
4
+
5
+ - Refactor implied property parsers (203fec9)
6
+ - Add `Helpers` module (caa1c02)
7
+ - New `PropertiesCollection` and `Property` instance methods (e9bb38b):
8
+ - `PropertiesCollection#plain_text_properties`
9
+ - `PropertiesCollection#url_properties`
10
+ - `Property#date_time_property?`
11
+ - `Property#embedded_markup_property?`
12
+ - `Property#plain_text_property?`
13
+ - `Property#url_property?`
14
+ - Remove Addressable (66c2bb4)
15
+ - Refactor classes to use nokogiri-html-ext (33fdf4a)
16
+ - Update activesupport (563bf56)
17
+ - **Breaking change:** Set minimum supported Ruby to 2.7 (ba17d05)
18
+ - Update development Ruby to 2.7.6 (ba17d05)
19
+ - Remove Reek (c1e76c5)
20
+ - Update runtime dependency version constraints (f83f26a)
21
+ - ~~**Breaking change:** Set minimum supported Ruby to 2.6~~ (fc588cd)
22
+ - ~~Update development Ruby to 2.6.10~~ (d05a2ac)
23
+
24
+ ## 1.1.0 / 2021-06-10
25
+
26
+ - Replace Absolutely dependency with Addressable (e93721b)
27
+ - Add support for Ruby 3.0 (d897c54)
28
+ - Update development Ruby version to 2.6.10 (051c9ad)
29
+
30
+ ## 1.0.0 / 2020-11-08
31
+
32
+ - Add `MicroMicro::Item#plain_text_properties` and `MicroMicro::Item#url_properties` methods (351e1f1)
33
+ - Add `MicroMicro::Collections::RelationshipsCollection#rels` and `MicroMicro::Collections::RelationshipsCollection#urls` methods(c0e5665)
34
+ - Add `MicroMicro::Collections::PropertiesCollection#names` and `MicroMicro::Collections::PropertiesCollection#values` methods (65486bc)
35
+ - Add `MicroMicro::Collections::ItemsCollection#types` method (6b53a81)
36
+ - Update absolutely dependency (4e67bb2)
37
+ - Add `Collectible` concern and refactor using Composite design pattern (82503b8)
38
+ - Update absolutely dependency (4578fb4)
39
+
3
40
  ## 0.1.0 / 2020-05-06
4
41
 
5
42
  - Initial release!
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.5.8 and is additionally tested against Ruby 2.6 and 2.7 using [Travis CI](https://travis-ci.com/jgarber623/micromicro).
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.5.8. 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.5.8 using your method of choice, install the project's gems by running:
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
data/README.md CHANGED
@@ -1,42 +1,43 @@
1
1
  # MicroMicro
2
2
 
3
- **A Ruby gem for extracting [microformats2](http://microformats.org/wiki/microformats2)-encoded data from HTML documents.**
3
+ **A Ruby gem for extracting [microformats2](https://microformats.org/wiki/microformats2)-encoded data from HTML documents.**
4
4
 
5
- [![Build](https://img.shields.io/travis/com/jgarber623/micromicro/master.svg?style=for-the-badge)](https://travis-ci.com/jgarber623/micromicro)
6
- [![Dependencies](https://img.shields.io/depfu/jgarber623/micromicro.svg?style=for-the-badge)](https://depfu.com/github/jgarber623/micromicro)
7
- [![Maintainability](https://img.shields.io/codeclimate/maintainability/jgarber623/micromicro.svg?style=for-the-badge)](https://codeclimate.com/github/jgarber623/micromicro)
8
- [![Coverage](https://img.shields.io/codeclimate/c/jgarber623/micromicro.svg?style=for-the-badge)](https://codeclimate.com/github/jgarber623/micromicro/code)
5
+ [![Gem](https://img.shields.io/gem/v/micromicro.svg?logo=rubygems&style=for-the-badge)](https://rubygems.org/gems/micromicro)
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/github/workflow/status/jgarber623/micromicro/CI?logo=github&style=for-the-badge)](https://github.com/jgarber623/micromicro/actions/workflows/ci.yml)
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
+ [![Coverage](https://img.shields.io/codeclimate/c/jgarber623/micromicro.svg?logo=code-climate&style=for-the-badge)](https://codeclimate.com/github/jgarber623/micromicro/code)
9
10
 
10
11
  ## Key Features
11
12
 
12
- - Parses microformats2-encoded HTML documents according to the [microformats2 parsing specification](http://microformats.org/wiki/microformats2-parsing)
13
+ - Parses microformats2-encoded HTML documents according to the [microformats2 parsing specification](https://microformats.org/wiki/microformats2-parsing)
13
14
  - Passes all microformats2 tests from [the official test suite](https://github.com/microformats/tests)¹
14
- - Supports Ruby 2.5 and newer
15
+ - Supports Ruby 2.7 and newer
15
16
 
16
- **Note:** MicroMicro **does not** parse [Classic Microformats](http://microformats.org/wiki/Main_Page#Classic_Microformats) (referred to in [the parsing specification](http://microformats.org/wiki/microformats2-parsing#note_backward_compatibility_details) as "backcompat root classes" and "backcompat properties"). If parsing documents marked up in this fashion, consider using [the official microformats-ruby parser](https://github.com/microformats/microformats-ruby).
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).
17
18
 
18
19
  <small>¹ …with some exceptions until [this pull request](https://github.com/microformats/tests/pull/112) is merged.</small>
19
20
 
20
21
  ## Getting Started
21
22
 
22
- 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).
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).
23
24
 
24
- MicroMicro is developed using Ruby 2.5.8 and is additionally tested against Ruby 2.6 and 2.7 using [Travis CI](https://travis-ci.com/jgarber623/micromicro).
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).
25
26
 
26
27
  ## Installation
27
28
 
28
- If you're using [Bundler](https://bundler.io), add MicroMicro to your project's `Gemfile`:
29
+ If you're using [Bundler](https://bundler.io) to manage gem dependencies, add MicroMicro to your project's Gemfile:
29
30
 
30
31
  ```ruby
31
- source 'https://rubygems.org'
32
-
33
32
  gem 'micromicro'
34
33
  ```
35
34
 
36
- …and hop over to your command prompt and run…
35
+ …and run `bundle install` in your shell.
36
+
37
+ To install the gem manually, run the following in your shell:
37
38
 
38
39
  ```sh
39
- $ bundle install
40
+ gem install micromicro
40
41
  ```
41
42
 
42
43
  ## Usage
@@ -53,7 +54,7 @@ An example using a simple `String` of HTML as input:
53
54
  require 'micromicro'
54
55
 
55
56
  doc = MicroMicro.parse('<div class="h-card">Jason Garber</div>', 'https://sixtwothree.org')
56
- #=> #<MicroMicro::Document items: #<MicroMicro::Collections::ItemsCollection count: 1, members: [#<MicroMicro::Item types: ["h-card"], properties: 1, children: 0>]>, relations: #<MicroMicro::Collections::RelationsCollection count: 0, members: []>>
57
+ #=> #<MicroMicro::Document items: #<MicroMicro::Collections::ItemsCollection count: 1, members: [#<MicroMicro::Item types: ["h-card"], properties: 1, children: 0>]>, relationships: #<MicroMicro::Collections::RelationshipsCollection count: 0, members: []>>
57
58
 
58
59
  doc.to_h
59
60
  #=> { :items => [{ :type => ["h-card"], :properties => { :name => ["Jason Garber"] } }], :rels => {}, :"rel-urls" => {} }
@@ -64,14 +65,14 @@ The `Hash` produced by calling `doc.to_h` may be converted to JSON (e.g. `doc.to
64
65
  Another example pulling the source HTML from [Tantek](https://tantek.com)'s website:
65
66
 
66
67
  ```ruby
67
- require "net/http"
68
- require "micromicro"
68
+ require 'net/http'
69
+ require 'micromicro'
69
70
 
70
- url = "https://tantek.com"
71
+ url = 'https://tantek.com'
71
72
  rsp = Net::HTTP.get(URI.parse(url))
72
73
 
73
74
  doc = MicroMicro.parse(rsp, url)
74
- #=> #<MicroMicro::Document items: #<MicroMicro::Collections::ItemsCollection count: 1, members: […]>, relations: #<MicroMicro::Collections::RelationsCollection count: 31, members: […]>>
75
+ #=> #<MicroMicro::Document items: #<MicroMicro::Collections::ItemsCollection count: 1, members: […]>, relationships: #<MicroMicro::Collections::RelationshipsCollection count: 31, members: […]>>
75
76
 
76
77
  doc.to_h
77
78
  #=> { :items => [{ :type => ["h-card"], :properties => {…}, :children => […]}], :rels => {…}, :'rel-urls' => {…} }
@@ -81,39 +82,74 @@ doc.to_h
81
82
 
82
83
  Building on the example above, a MicroMicro-parsed document is navigable and manipulable using a familiar `Enumerable`-esque interface.
83
84
 
85
+ #### Items
86
+
84
87
  ```ruby
85
88
  doc.items.first
86
89
  #=> #<MicroMicro::Item types: ["h-card"], properties: 42, children: 6>
87
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
88
102
  doc.items.first.properties
89
103
  #=> #<MicroMicro::Collections::PropertiesCollection count: 42, members: […]>
90
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
+
91
121
  doc.items.first.properties[7]
92
122
  #=> #<MicroMicro::Property name: "category", prefix: "p", value: "teacher">
93
123
 
94
124
  doc.items.first.properties.take(5).map { |property| [property.name, property.value] }
95
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
+ ```
96
127
 
97
- doc.items.first.children
98
- #=> #<MicroMicro::Collections::ItemsCollection count: 6, members: […]>
128
+ #### Relationships
99
129
 
100
- doc.relations.first
101
- #=> #<MicroMicro::Relation href: "https://tantek.com/", rels: ["canonical"]>
130
+ ```ruby
131
+ doc.relationships.first
132
+ #=> #<MicroMicro::Relationship href: "https://tantek.com/", rels: ["canonical"]>
102
133
 
103
- doc.relations.map(&:rels).flatten.uniq.sort
134
+ # 🆕 in v1.0.0
135
+ doc.relationships.rels
104
136
  #=> ["alternate", "apple-touch-icon-precomposed", "author", "authorization_endpoint", "bookmark", "canonical", "hub", "icon", "me", "microsub", …]
105
137
 
106
- doc.relations.find { |relation| relation.rels.include?('webmention') }
107
- # => #<MicroMicro::Relation href: "https://webmention.io/tantek.com/webmention", rels: ["webmention"]>
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"]>
108
144
  ```
109
145
 
110
146
  ## Contributing
111
147
 
112
- Interested in helping improve MicroMicro? Awesome! Your help is greatly appreciated. See [CONTRIBUTING.md](https://github.com/jgarber623/micromicro/blob/master/CONTRIBUTING.md) for details.
148
+ Interested in helping improve MicroMicro? Awesome! Your help is greatly appreciated. See [CONTRIBUTING.md](https://github.com/jgarber623/micromicro/blob/main/CONTRIBUTING.md) for details.
113
149
 
114
150
  ## Acknowledgments
115
151
 
116
- MicroMicro wouldn't exist without the hard work of everyone involved in the [microformats](http://microformats.org) community. Additionally, the comprehensive [microformats test suite](https://github.com/microformats/tests) was invaluable in the development of this Ruby gem.
152
+ MicroMicro wouldn't exist without the hard work of everyone involved in the [microformats](https://microformats.org) community. Additionally, the comprehensive [microformats test suite](https://github.com/microformats/tests) was invaluable in the development of this Ruby gem.
117
153
 
118
154
  MicroMicro is written and maintained by [Jason Garber](https://sixtwothree.org).
119
155
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MicroMicro
4
+ module Collectible
5
+ attr_accessor :collection
6
+
7
+ def next_all
8
+ collection.split(self).last
9
+ end
10
+
11
+ def prev_all
12
+ collection.split(self).first
13
+ end
14
+ end
15
+ end
@@ -1,37 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Collections
3
5
  class BaseCollection
6
+ extend Forwardable
7
+
4
8
  include Enumerable
5
9
 
6
- delegate :[], :each, :last, :length, :split, to: :members
10
+ def_delegators :members, :[], :each, :last, :length, :split
7
11
 
8
- # @param members [Array<MicroMicro::Item, MicroMicro::Property, MicroMicro::Relation>]
12
+ # @param members [Array<MicroMicro::Item, MicroMicro::Property, MicroMicro::Relationship>]
9
13
  def initialize(members = [])
10
- @members = members
11
-
12
- decorate_members if respond_to?(:decorate_members, true)
14
+ members.each { |member| push(member) }
13
15
  end
14
16
 
17
+ # :nocov:
15
18
  # @return [String]
16
19
  def inspect
17
- format(%(#<#{self.class.name}:%#0x count: #{count}, members: #{members.inspect}>), object_id)
20
+ "#<#{self.class}:#{format('%#0x', object_id)} " \
21
+ "count: #{count}, " \
22
+ "members: #{members.inspect}>"
18
23
  end
24
+ # :nocov:
19
25
 
20
- # @param member [MicroMicro::Item, MicroMicro::Property, MicroMicro::Relation]
21
- # @return [self]
26
+ # @param member [MicroMicro::Item, MicroMicro::Property, MicroMicro::Relationship]
22
27
  def push(member)
23
- members.push(member)
28
+ members << member
24
29
 
25
- decorate_members if respond_to?(:decorate_members, true)
26
-
27
- self
30
+ member.collection = self
28
31
  end
29
32
 
30
33
  alias << push
31
34
 
32
35
  private
33
36
 
34
- attr_reader :members
37
+ def members
38
+ @members ||= []
39
+ end
35
40
  end
36
41
  end
37
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Collections
3
5
  class ItemsCollection < BaseCollection
@@ -5,6 +7,11 @@ module MicroMicro
5
7
  def to_a
6
8
  map(&:to_h)
7
9
  end
10
+
11
+ # @return [Array<String>]
12
+ def types
13
+ @types ||= flat_map(&:types).uniq.sort
14
+ end
8
15
  end
9
16
  end
10
17
  end
@@ -1,17 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  module Collections
3
5
  class PropertiesCollection < BaseCollection
6
+ # @return [Array<String>]
7
+ def names
8
+ @names ||= map(&:name).uniq.sort
9
+ end
10
+
11
+ # @return [MicroMicro::Collections::PropertiesCollection]
12
+ def plain_text_properties
13
+ self.class.new(select(&:plain_text_property?))
14
+ end
15
+
4
16
  # @return [Hash{Symbol => Array<String, Hash>}]
5
17
  def to_h
6
- group_by(&:name).symbolize_keys.deep_transform_values do |property|
7
- property.item_node? ? property.value.to_h : property.value
8
- end
18
+ group_by(&:name).symbolize_keys.deep_transform_values(&:value)
9
19
  end
10
20
 
11
- private
21
+ # @return [MicroMicro::Collections::PropertiesCollection]
22
+ def url_properties
23
+ self.class.new(select(&:url_property?))
24
+ end
12
25
 
13
- def decorate_members
14
- each { |member| member.collection = self }
26
+ # @return [Array<String, Hash>]
27
+ def values
28
+ @values ||= map(&:value).uniq
15
29
  end
16
30
  end
17
31
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MicroMicro
4
+ module Collections
5
+ class RelationshipsCollection < BaseCollection
6
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_a_hyperlink_element_for_rel_microformats
7
+ #
8
+ # @return [Hash{Symbol => Array<String>}]
9
+ def group_by_rel
10
+ each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |member, hash|
11
+ member.rels.each { |rel| hash[rel] << member.href }
12
+ end.symbolize_keys.transform_values(&:uniq)
13
+ end
14
+
15
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_a_hyperlink_element_for_rel_microformats
16
+ #
17
+ # @return [Hash{Symbol => Hash{Symbol => Array, String}}]
18
+ def group_by_url
19
+ group_by(&:href).symbolize_keys.transform_values { |relationships| relationships.first.to_h.slice!(:href) }
20
+ end
21
+
22
+ # @return [Array<String>]
23
+ def rels
24
+ @rels ||= flat_map(&:rels).uniq.sort
25
+ end
26
+
27
+ # @return [Array<String>]
28
+ def urls
29
+ @urls ||= map(&:href).uniq.sort
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,71 +1,63 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  class Document
3
- # @param markup [String] the HTML to parse
4
- # @param base_url [String] the URL associated with the provided markup
5
+ # Parse a string of HTML for microformats2-encoded data.
6
+ #
7
+ # MicroMicro::Document.new('<a href="/" class="h-card" rel="me">Jason Garber</a>', 'https://sixtwothree.org')
8
+ #
9
+ # Or, pull the source HTML of a page on the Web:
10
+ #
11
+ # url = 'https://tantek.com'
12
+ # markup = Net::HTTP.get(URI.parse(url))
13
+ #
14
+ # doc = MicroMicro::Document.new(markup, url)
15
+ #
16
+ # @param markup [String] The HTML to parse for microformats2-encoded data.
17
+ # @param base_url [String] The URL associated with markup. Used for relative URL resolution.
5
18
  def initialize(markup, base_url)
6
- @markup = markup
7
- @base_url = base_url
19
+ @document = Nokogiri::HTML(markup, base_url).resolve_relative_urls!
8
20
  end
9
21
 
22
+ # :nocov:
10
23
  # @return [String]
11
24
  def inspect
12
- format(%(#<#{self.class.name}:%#0x items: #{items.inspect}, relations: #{relations.inspect}>), object_id)
25
+ "#<#{self.class}:#{format('%#0x', object_id)} " \
26
+ "items: #{items.inspect}, " \
27
+ "relationships: #{relationships.inspect}>"
13
28
  end
29
+ # :nocov:
14
30
 
31
+ # A collection of items parsed from the provided markup.
32
+ #
15
33
  # @return [MicroMicro::Collections::ItemsCollection]
16
34
  def items
17
- @items ||= Collections::ItemsCollection.new(Item.items_from(document))
35
+ @items ||= Collections::ItemsCollection.new(Item.from_context(document.element_children))
18
36
  end
19
37
 
20
- # @return [MicroMicro::Collections::RelationsCollection]
21
- def relations
22
- @relations ||= Collections::RelationsCollection.new(Relation.relations_from(document))
38
+ # A collection of relationships parsed from the provided markup.
39
+ #
40
+ # @return [MicroMicro::Collections::RelationshipsCollection]
41
+ def relationships
42
+ @relationships ||= Collections::RelationshipsCollection.new(Relationship.relationships_from(document))
23
43
  end
24
44
 
25
- # @see microformats2 Parsing Specification section 1.1
26
- # @see http://microformats.org/wiki/microformats2-parsing#parse_a_document_for_microformats
45
+ # Return the parsed document as a Hash.
46
+ #
47
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_a_document_for_microformats
27
48
  #
28
- # @return [Hash]
49
+ # @return [Hash{Symbol => Array, Hash}]
29
50
  def to_h
30
51
  {
31
52
  items: items.to_a,
32
- rels: relations.group_by_rel,
33
- 'rel-urls': relations.group_by_url
53
+ rels: relationships.group_by_rel,
54
+ 'rel-urls': relationships.group_by_url
34
55
  }
35
56
  end
36
57
 
37
- # @param node [Nokogiri::XML::Element]
38
- # @return [Boolean]
39
- def self.ignore_node?(node)
40
- ignored_node_names.include?(node.name)
41
- end
42
-
43
- # @return [Array<String>]
44
- def self.ignored_node_names
45
- %w[script style template]
46
- end
47
-
48
58
  private
49
59
 
50
- attr_reader :base_url, :markup
51
-
52
- # @return [Nokogiri::XML::Element, nil]
53
- def base_element
54
- @base_element ||= Nokogiri::HTML(markup).at_css('base[href]')
55
- end
56
-
57
60
  # @return [Nokogiri::HTML::Document]
58
- def document
59
- @document ||= Nokogiri::HTML(markup, resolved_base_url)
60
- end
61
-
62
- # @return [String]
63
- def resolved_base_url
64
- @resolved_base_url ||= begin
65
- return base_url unless base_element
66
-
67
- Absolutely.to_abs(base: base_url, relative: base_element['href'])
68
- end
69
- end
61
+ attr_reader :document
70
62
  end
71
63
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MicroMicro
4
+ module Helpers
5
+ IGNORED_NODE_NAMES = %w[script style template].freeze
6
+
7
+ # @param node [Nokogiri::XML::Element]
8
+ # @param attributes_map [Hash{String => Array}]
9
+ # @return [String, nil]
10
+ def self.attribute_value_from(node, attributes_map)
11
+ attributes_map.filter_map do |attribute, names|
12
+ node[attribute] if names.include?(node.name) && node[attribute]
13
+ end.first
14
+ end
15
+
16
+ # @param node [Nokogiri::XML::Element]
17
+ # @return [Boolean]
18
+ def self.ignore_node?(node)
19
+ IGNORED_NODE_NAMES.include?(node.name)
20
+ end
21
+
22
+ # @param nodes [Nokogiri::XML::NodeSet]
23
+ # @return [Boolean]
24
+ def self.ignore_nodes?(nodes)
25
+ (nodes.map(&:name) & IGNORED_NODE_NAMES).any?
26
+ end
27
+
28
+ # @param node [Nokogiri::XML::Element]
29
+ # @return [Boolean]
30
+ def self.item_node?(node)
31
+ root_class_names_from(node).any?
32
+ end
33
+
34
+ # @param node [Nokogiri::XML::Element]
35
+ # @return [Array<String>]
36
+ def self.property_class_names_from(node)
37
+ node.classes.grep(/^(?:dt|e|p|u)(?:-[0-9a-z]+)?(?:-[a-z]+)+$/).uniq
38
+ end
39
+
40
+ # @param node [Nokogiri::XML::Element]
41
+ # @return [Boolean]
42
+ def self.property_node?(node)
43
+ property_class_names_from(node).any?
44
+ end
45
+
46
+ # @param node [Nokogiri::XML::Element]
47
+ # @return [Array<String>]
48
+ def self.root_class_names_from(node)
49
+ node.classes.grep(/^h(?:-[0-9a-z]+)?(?:-[a-z]+)+$/).uniq.sort
50
+ end
51
+
52
+ # @see https://microformats.org/wiki/microformats2-parsing#parse_an_element_for_properties
53
+ # @see https://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
54
+ #
55
+ # @param context [Nokogiri::HTML::Document, Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
56
+ # @yield [context]
57
+ # @return [String]
58
+ def self.text_content_from(context)
59
+ context.css(*IGNORED_NODE_NAMES).unlink
60
+
61
+ yield(context) if block_given?
62
+
63
+ context.text.strip
64
+ end
65
+
66
+ # @see https://microformats.org/wiki/value-class-pattern#Basic_Parsing
67
+ #
68
+ # @param node [Nokogiri::XML::Element]
69
+ # @return [Boolean]
70
+ def self.value_class_node?(node)
71
+ node.classes.include?('value')
72
+ end
73
+
74
+ # @see https://microformats.org/wiki/value-class-pattern#Parsing_value_from_a_title_attribute
75
+ #
76
+ # @param node [Nokogiri::XML::Element]
77
+ # @return [Boolean]
78
+ def self.value_title_node?(node)
79
+ node.classes.include?('value-title')
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MicroMicro
2
4
  class ImpliedProperty < Property
3
5
  IMPLIED_PROPERTY_PARSERS_MAP = {