elcamino-microformat 0.0.8
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 +7 -0
- data/.gitignore +18 -0
- data/.rvmrc +12 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +55 -0
- data/Rakefile +13 -0
- data/lib/microformat.rb +11 -0
- data/lib/microformat/attribute.rb +50 -0
- data/lib/microformat/attribute_definition.rb +23 -0
- data/lib/microformat/attribute_map.rb +40 -0
- data/lib/microformat/card.rb +36 -0
- data/lib/microformat/collection.rb +26 -0
- data/lib/microformat/format.rb +48 -0
- data/lib/microformat/parser.rb +54 -0
- data/lib/microformat/review.rb +19 -0
- data/lib/microformat/review_aggregate.rb +16 -0
- data/lib/microformat/selectors.rb +45 -0
- data/lib/microformat/version.rb +3 -0
- data/microformat.gemspec +26 -0
- data/spec/microformat/attribute_definition_spec.rb +16 -0
- data/spec/microformat/attribute_spec.rb +23 -0
- data/spec/microformat/collection_spec.rb +31 -0
- data/spec/microformat/format_spec.rb +46 -0
- data/spec/microformat/parser_spec.rb +121 -0
- data/spec/microformat/selectors_spec.rb +92 -0
- data/spec/microformat_spec.rb +17 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/env.rb +8 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b953eda6079522b0e0d424163f04636dbe335b4c
|
4
|
+
data.tar.gz: b6617bfe82b414dbb901a06079a730b58395421e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e2993d9b04c721e7ca88bc54f9ab350a9279d4e1ce8c2d620b393af6d66829cba7240ceb71f0050e6fe99f9e75093524d81d3c6d5a6e9cb3460f649bf12e6c1f
|
7
|
+
data.tar.gz: 07bd2728b89221ddd090d635644fb5fa1c226fd1d7f4e6e0e33acd52c1cc22293aa7f90ba0391aec21522f8fd0195ae2df630b16780e32b6e7bfbca339beced8
|
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
if ! rvm list | grep -q ruby-1.9.3-p194 ; then
|
4
|
+
rvm install 1.9.3-p194
|
5
|
+
fi
|
6
|
+
|
7
|
+
rvm 1.9.3-p194@platformq_microformat --create
|
8
|
+
|
9
|
+
if ! gem list | grep -q bundler ; then
|
10
|
+
gem install --no-ri --no-rdoc bundler
|
11
|
+
bundle install --without production
|
12
|
+
fi
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Platform Q LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Microformat
|
2
|
+
|
3
|
+
Reads Microformats from HTML documents
|
4
|
+
|
5
|
+
[![Build Status][2]][1] [![Code Climate][3]][4]
|
6
|
+
|
7
|
+
[1]: http://travis-ci.org/platformq/microformat
|
8
|
+
[2]: https://secure.travis-ci.org/platformq/microformat.png?branch=master
|
9
|
+
[3]: https://codeclimate.com/badge.png
|
10
|
+
[4]: https://codeclimate.com/github/platformq/microformat
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem "microformat"
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install microformat
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
You can parse a document (or partial document), providing the HTML as a string:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
html = "<html>...</html>"
|
34
|
+
Microformat.parse(html) # => Microformat::Collection
|
35
|
+
```
|
36
|
+
|
37
|
+
Or provide a Nokogiri element:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
require "nokogiri"
|
41
|
+
|
42
|
+
html = "<html>...</html>"
|
43
|
+
doc = Nokogiri::HTML(html)
|
44
|
+
element = doc.css("body")
|
45
|
+
Microformat.parse(element)
|
46
|
+
# => Microformat::Collection
|
47
|
+
```
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
6
|
+
desc "Runs all the specs"
|
7
|
+
task default: %w(spec)
|
8
|
+
|
9
|
+
desc "Run specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
12
|
+
# Put spec opts in a file named .rspec in root
|
13
|
+
end
|
data/lib/microformat.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "microformat/attribute_map"
|
2
|
+
|
3
|
+
module Microformat
|
4
|
+
class Attribute
|
5
|
+
attr_reader :name, :options, :attributes
|
6
|
+
|
7
|
+
def initialize(name, options = {}, &block)
|
8
|
+
@name = name
|
9
|
+
@options = options
|
10
|
+
@attributes ||= {}
|
11
|
+
if options[:format]
|
12
|
+
@attributes.merge!(options[:format].attribute_definition.attributes)
|
13
|
+
end
|
14
|
+
block.yield(self) if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute(name, options = {}, &block)
|
18
|
+
Attribute.new(name, options, &block).tap do |attribute|
|
19
|
+
@attributes.merge!(name.to_sym => attribute)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_from(document)
|
24
|
+
selector = options[:selector] || ".#{@name}"
|
25
|
+
sub_document = document.css(selector).first
|
26
|
+
value = read_value_from(sub_document)
|
27
|
+
AttributeMap.new(self, sub_document, { value: value })
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_value_from(document)
|
31
|
+
Array(options[:attribute] || "text").each do |attr|
|
32
|
+
if attr == "text"
|
33
|
+
return cast((document && document.text) || options[:default], options[:cast])
|
34
|
+
elsif document[attr]
|
35
|
+
return cast(document && document[attr], options[:cast])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return options[:default]
|
39
|
+
end
|
40
|
+
|
41
|
+
def cast(value, cast_to = nil)
|
42
|
+
value && case cast_to
|
43
|
+
when :integer then value.to_s.strip.to_i
|
44
|
+
when :decimal then value.to_s.strip.to_f
|
45
|
+
when :string then value.to_s.strip
|
46
|
+
else value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "microformat/attribute"
|
2
|
+
require "microformat/attribute_map"
|
3
|
+
|
4
|
+
module Microformat
|
5
|
+
class AttributeDefinition
|
6
|
+
attr_reader :attributes
|
7
|
+
|
8
|
+
def initialize(&block)
|
9
|
+
@attributes ||= {}
|
10
|
+
block.yield(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def attribute(name, options = {}, &block)
|
14
|
+
Attribute.new(name, options, &block).tap do |attribute|
|
15
|
+
@attributes.merge!(name.to_sym => attribute)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def map_to(document)
|
20
|
+
AttributeMap.new(self, document)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Microformat
|
2
|
+
class AttributeMap
|
3
|
+
attr_reader :definition, :document
|
4
|
+
|
5
|
+
def initialize(definition, document, values = {})
|
6
|
+
@definition = definition
|
7
|
+
@document = document
|
8
|
+
@values = values
|
9
|
+
@attribute_cache = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def respond_to_missing?(name, public_only = false)
|
13
|
+
values_responds_to?(name) ||
|
14
|
+
definition_responds_to?(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(name, *args, &block)
|
18
|
+
if values_responds_to?(name)
|
19
|
+
@values.fetch(name.to_sym)
|
20
|
+
elsif @attribute_cache.has_key?(name)
|
21
|
+
@attribute_cache[name]
|
22
|
+
elsif definition_responds_to?(name)
|
23
|
+
attribute = @definition.attributes.fetch(name)
|
24
|
+
value = attribute.read_from(document)
|
25
|
+
@attribute_cache[name] = value
|
26
|
+
else
|
27
|
+
super(name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def values_responds_to?(name)
|
33
|
+
@values.has_key?(name.to_sym)
|
34
|
+
end
|
35
|
+
|
36
|
+
def definition_responds_to?(name)
|
37
|
+
@definition.attributes.has_key?(name.to_sym)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "microformat/format"
|
2
|
+
|
3
|
+
module Microformat
|
4
|
+
class Card < Format
|
5
|
+
selector ".vcard"
|
6
|
+
|
7
|
+
attribute_definition do |root|
|
8
|
+
root.attribute(:fn, required: true)
|
9
|
+
root.attribute(:n) do |n|
|
10
|
+
n.attribute(:"honorific-prefix")
|
11
|
+
n.attribute(:"given-name")
|
12
|
+
n.attribute(:"additional-name")
|
13
|
+
n.attribute(:"family-name")
|
14
|
+
n.attribute(:"honorific-suffix")
|
15
|
+
end
|
16
|
+
root.attribute(:nickname)
|
17
|
+
root.attribute(:org)
|
18
|
+
root.attribute(:photo, cast: :url, attribute: ["href", "src"])
|
19
|
+
root.attribute(:url, cast: :url, attribute: "href")
|
20
|
+
root.attribute(:email, cast: :email)
|
21
|
+
root.attribute(:tel, cast: :tel)
|
22
|
+
root.attribute(:categoria)
|
23
|
+
root.attribute(:adr) do |adr|
|
24
|
+
adr.attribute(:"street-address")
|
25
|
+
adr.attribute(:locality)
|
26
|
+
adr.attribute(:region)
|
27
|
+
adr.attribute(:"postal-code")
|
28
|
+
adr.attribute(:"country-name")
|
29
|
+
adr.attribute(:district)
|
30
|
+
end
|
31
|
+
root.attribute(:"bday")
|
32
|
+
root.attribute(:"category")
|
33
|
+
root.attribute(:"note")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "microformat/selectors"
|
2
|
+
|
3
|
+
module Microformat
|
4
|
+
class Collection < ::Array
|
5
|
+
def <<(element)
|
6
|
+
# load the first matching format
|
7
|
+
format = Selectors.class_matching(element)
|
8
|
+
# use the microformat to parse the element
|
9
|
+
parsed = format.parse(element)
|
10
|
+
# add the parsed object to the array
|
11
|
+
super(parsed)
|
12
|
+
end
|
13
|
+
|
14
|
+
def filter(*args)
|
15
|
+
classes = Array(args).flatten
|
16
|
+
# find the applicable classes
|
17
|
+
filtered = select do |object|
|
18
|
+
Array(classes).include?(object.class)
|
19
|
+
end
|
20
|
+
# create a new collection from them
|
21
|
+
self.class.new.tap do |collection|
|
22
|
+
collection.replace(filtered)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "microformat/attribute_definition"
|
2
|
+
require "microformat/selectors"
|
3
|
+
|
4
|
+
module Microformat
|
5
|
+
class Format
|
6
|
+
def self.selector(selector = nil)
|
7
|
+
define_selector(selector) if selector
|
8
|
+
@selector
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.attribute_definition(&block)
|
12
|
+
@attribute_definition = AttributeDefinition.new(&block) if block_given?
|
13
|
+
@attribute_definition
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.parse(document)
|
17
|
+
new(document)
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :document
|
21
|
+
|
22
|
+
def initialize(document)
|
23
|
+
@document = document
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(name, public_only = false)
|
27
|
+
attribute_map.respond_to?(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name)
|
31
|
+
if attribute_map.respond_to?(name)
|
32
|
+
attribute_map.send(name)
|
33
|
+
else
|
34
|
+
super(name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def attribute_map
|
40
|
+
@attribute_map ||= self.class.attribute_definition.map_to(document)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.define_selector(selector)
|
44
|
+
Selectors.define(selector, self)
|
45
|
+
@selector = selector
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "microformat/collection"
|
3
|
+
require "microformat/selectors"
|
4
|
+
|
5
|
+
module Microformat
|
6
|
+
class Parser
|
7
|
+
def self.parse(doc, options = {})
|
8
|
+
# ensure the document is parsed
|
9
|
+
unless doc.respond_to?(:css)
|
10
|
+
doc = Nokogiri::HTML(doc)
|
11
|
+
end
|
12
|
+
# return the collection
|
13
|
+
new(doc, options).collection
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :doc, :options
|
17
|
+
|
18
|
+
def initialize(doc, options)
|
19
|
+
@doc = doc
|
20
|
+
@options = options
|
21
|
+
parse(elements)
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(elements)
|
25
|
+
i = 0; while i < [limit, elements.size].min do
|
26
|
+
collection << elements[i]
|
27
|
+
i += 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def limit
|
32
|
+
@limit ||= options[:limit] || Float::INFINITY
|
33
|
+
end
|
34
|
+
|
35
|
+
def selectors
|
36
|
+
@selectors ||= Selectors.filter(options[:filter])
|
37
|
+
end
|
38
|
+
|
39
|
+
def collection
|
40
|
+
@collection ||= Collection.new
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def elements
|
45
|
+
@elements ||= [].tap do |elements|
|
46
|
+
while doc.css(selectors.join(", ")).length > 0
|
47
|
+
node = doc.css(selectors.join(", ")).first
|
48
|
+
node.remove
|
49
|
+
elements.push node
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "microformat/format"
|
2
|
+
require "microformat/card"
|
3
|
+
|
4
|
+
module Microformat
|
5
|
+
class Review < Format
|
6
|
+
selector ".hreview"
|
7
|
+
|
8
|
+
attribute_definition do |root|
|
9
|
+
root.attribute(:summary)
|
10
|
+
root.attribute(:type)
|
11
|
+
root.attribute(:item, format: Card)
|
12
|
+
root.attribute(:reviewer, format: Card)
|
13
|
+
root.attribute(:rating, cast: :decimal)
|
14
|
+
root.attribute(:description)
|
15
|
+
root.attribute(:tags, multiple: true, selector: "[rel='tag']")
|
16
|
+
root.attribute(:permalink, selector: "[rel='bookmark']", attribute: "href")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "microformat/format"
|
2
|
+
require "microformat/card"
|
3
|
+
|
4
|
+
module Microformat
|
5
|
+
class ReviewAggregate < Format
|
6
|
+
selector ".hreview-aggregate"
|
7
|
+
|
8
|
+
attribute_definition do |root|
|
9
|
+
root.attribute(:item, format: Card)
|
10
|
+
root.attribute(:rating, cast: :decimal)
|
11
|
+
root.attribute(:count, cast: :integer)
|
12
|
+
root.attribute(:votes, cast: :integer)
|
13
|
+
root.attribute(:summary)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
module Microformat
|
4
|
+
class Selectors < Hash
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.class_matching(element)
|
8
|
+
# load the CSS classes of the element
|
9
|
+
css_classes = element["class"].split(/\s+/).map do |c|
|
10
|
+
".#{c}"
|
11
|
+
end
|
12
|
+
# loop through the classes
|
13
|
+
Array(css_classes).each do |css_class|
|
14
|
+
instance.each do |selector, klass|
|
15
|
+
if selector == css_class
|
16
|
+
return klass
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
raise RuntimeError, "No class is defined for any of the selectors: #{css_classes.join(" / ")}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.define(selector, klass)
|
24
|
+
if instance.has_key?(selector) && instance.fetch(selector) != klass
|
25
|
+
raise ArgumentError, "#{instance.fetch(selector).name} has already implemented the selector '#{selector}'"
|
26
|
+
else
|
27
|
+
instance.merge!(selector => klass)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.filter(klasses = nil)
|
32
|
+
if klasses
|
33
|
+
instance.filter(Array(klasses))
|
34
|
+
else
|
35
|
+
instance.keys
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def filter(klasses)
|
40
|
+
select do |selector, klass|
|
41
|
+
Array(klasses).include?(klass)
|
42
|
+
end.keys
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/microformat.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require "microformat/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.authors = ["Ryan Townsend", "Tobias Begalke"]
|
9
|
+
s.email = ["ryan@ryantownsend.co.uk", "elcamino@spyz.org"]
|
10
|
+
s.description = %q{Reads Microformats from HTML documents}
|
11
|
+
s.summary = s.description
|
12
|
+
s.homepage = "https://github.com/elcamino/microformat"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split($\)
|
15
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
17
|
+
s.name = "elcamino-microformat"
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.version = Microformat::VERSION
|
20
|
+
|
21
|
+
# gems
|
22
|
+
s.add_dependency "nokogiri"
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
s.add_development_dependency "simplecov"
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Microformat::AttributeDefinition do
|
4
|
+
subject { Microformat::AttributeDefinition }
|
5
|
+
|
6
|
+
describe "#initialize" do
|
7
|
+
it "should accept a block of nested attributes" do
|
8
|
+
map = subject.new do |map|
|
9
|
+
map.attribute(:one)
|
10
|
+
map.attribute(:two)
|
11
|
+
end
|
12
|
+
|
13
|
+
expect(map.attributes.size).to eq(2)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Microformat::Attribute do
|
4
|
+
subject { Microformat::Attribute }
|
5
|
+
|
6
|
+
describe "#initialize" do
|
7
|
+
it "should accept a block of nested attributes" do
|
8
|
+
attribute = subject.new(:name) do |attr|
|
9
|
+
attr.attribute(:one)
|
10
|
+
attr.attribute(:two)
|
11
|
+
attr.attribute(:three) do |three|
|
12
|
+
three.attribute(:four)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
expect(attribute.attributes.size).to eq(3)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set the name" do
|
20
|
+
expect(subject.new(:fn).name).to eq(:fn)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Microformat::Collection do
|
4
|
+
subject do
|
5
|
+
Microformat::Collection.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#<<" do
|
9
|
+
it "should parse the element to the collection" do
|
10
|
+
selector = ".selector"
|
11
|
+
source = %Q(<html><body>
|
12
|
+
<div class="#{selector.gsub(/^\./, "")}"></div>
|
13
|
+
</body></html>)
|
14
|
+
element = Nokogiri::HTML(source).css(selector).first
|
15
|
+
parsed = mock("parsed_object")
|
16
|
+
format = mock("format")
|
17
|
+
format.should_receive(:parse).and_return(parsed)
|
18
|
+
Microformat::Selectors.define(selector, format)
|
19
|
+
subject << element
|
20
|
+
expect(subject).to include parsed
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#filter" do
|
25
|
+
it "should filter the collection down to the specific classes" do
|
26
|
+
objects = [Object.new, Hash.new, Array.new]
|
27
|
+
subject.replace(objects)
|
28
|
+
expect(subject.filter(Hash)).to eq [objects[1]]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Microformat
|
4
|
+
class TestFormat < Microformat::Format; end
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Microformat::Format do
|
8
|
+
after(:each) do
|
9
|
+
Microformat::Selectors.instance.replace({})
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "::selector" do
|
13
|
+
describe "getting the value" do
|
14
|
+
it "should return the value" do
|
15
|
+
Microformat::TestFormat.selector ".review"
|
16
|
+
expect(Microformat::TestFormat.selector).to eq ".review"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "setting the value" do
|
21
|
+
it "should define the selector" do
|
22
|
+
Microformat::TestFormat.selector ".review2"
|
23
|
+
expect(Microformat::Selectors.instance[".review2"]).to eq Microformat::TestFormat
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "::attribute_definition" do
|
29
|
+
describe "setting the value" do
|
30
|
+
it "should accept a block and set the map correctly" do
|
31
|
+
map = Microformat::TestFormat.attribute_definition do |attr|
|
32
|
+
attr.attribute :name
|
33
|
+
end
|
34
|
+
expect(map.attributes.values.first.name).to eq :name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "::parse" do
|
40
|
+
it "should return and instance of the format using the given document" do
|
41
|
+
html = %Q(<html><body>Something</body></html>)
|
42
|
+
doc = Nokogiri::HTML(html)
|
43
|
+
expect(Microformat::TestFormat.parse(doc).document).to eq doc
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
describe Microformat::Parser do
|
5
|
+
describe "::parse" do
|
6
|
+
subject do
|
7
|
+
Microformat::Parser.parse(doc)
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
Microformat::Selectors.instance.replace({})
|
12
|
+
[
|
13
|
+
Microformat::Card,
|
14
|
+
Microformat::Review
|
15
|
+
].each { |klass| klass.selector(klass.selector) }
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:html) do
|
19
|
+
%Q(<html><body></body></html>)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:review_html) do
|
23
|
+
%Q(<html><body>
|
24
|
+
<div class="hreview">
|
25
|
+
<div class="summary">It's good</div>
|
26
|
+
<div class="reviewer">
|
27
|
+
<p class="fn">Dave</p>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</body></html>)
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:nested_review_html) do
|
34
|
+
%Q(<html><body>
|
35
|
+
<div class="hreview">
|
36
|
+
<div class="summary">It's good</div>
|
37
|
+
<div class="reviewer">
|
38
|
+
<p class="fn">Dave</p>
|
39
|
+
<div class="hreview"></div>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
</body></html>)
|
43
|
+
end
|
44
|
+
|
45
|
+
context "given a HTML string" do
|
46
|
+
let(:doc) { html }
|
47
|
+
|
48
|
+
it "should return an instance of Microformat::Collection" do
|
49
|
+
expect(subject).to be_kind_of Microformat::Collection
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "given a HTML document" do
|
54
|
+
let(:doc) { Nokogiri::HTML(html) }
|
55
|
+
|
56
|
+
it "should return an instance of Microformat::Collection" do
|
57
|
+
expect(subject).to be_kind_of Microformat::Collection
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "given a HTML element" do
|
62
|
+
let(:doc) { Nokogiri::HTML(html).css("body") }
|
63
|
+
|
64
|
+
it "should return an instance of Microformat::Collection" do
|
65
|
+
expect(subject).to be_kind_of Microformat::Collection
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "given a HTML document with a hReview" do
|
70
|
+
let(:doc) { Nokogiri::HTML(review_html) }
|
71
|
+
|
72
|
+
it "should return a collection with one object" do
|
73
|
+
expect(subject.size).to eq 1
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "the returned Microformat object" do
|
77
|
+
subject do
|
78
|
+
Microformat::Parser.parse(doc).first
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be a Microformat::Review" do
|
82
|
+
expect(subject).to be_kind_of(Microformat::Review)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return the summary" do
|
86
|
+
expect(subject.summary.value).to eq "It's good"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return the reviewer's full name" do
|
90
|
+
expect(subject.reviewer.fn.value).to eq "Dave"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "given a HTML document with nested microformats" do
|
96
|
+
let(:doc) { Nokogiri::HTML(nested_review_html) }
|
97
|
+
|
98
|
+
it "should return a collection with one object" do
|
99
|
+
expect(subject.size).to eq 1
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "the returned Microformat object" do
|
103
|
+
subject do
|
104
|
+
Microformat::Parser.parse(doc).first
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should be a Microformat::Review" do
|
108
|
+
expect(subject).to be_kind_of(Microformat::Review)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return the summary" do
|
112
|
+
expect(subject.summary.value).to eq "It's good"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return the reviewer's full name" do
|
116
|
+
expect(subject.reviewer.fn.value).to eq "Dave"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Microformat::Selectors do
|
4
|
+
let(:selectors) { Hash.new }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
Microformat::Selectors.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
selectors.each do |sel,klass|
|
12
|
+
Microformat::Selectors.define(sel, klass)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
Microformat::Selectors.instance.replace({})
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "::instance" do
|
21
|
+
it "should always return the same object" do
|
22
|
+
expect(subject.class.instance.object_id).to eq subject.class.instance.object_id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "::define" do
|
27
|
+
context "when the selector is already defined" do
|
28
|
+
it "should raise an exception" do
|
29
|
+
subject.class.define(".hello", Hash)
|
30
|
+
expect {
|
31
|
+
subject.class.define(".hello", Object)
|
32
|
+
}.to raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when redefining the selector" do
|
37
|
+
it "should not raise an exception" do
|
38
|
+
subject.class.define(".hello", Hash)
|
39
|
+
expect {
|
40
|
+
subject.class.define(".hello", Hash)
|
41
|
+
}.not_to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the selector is not defined" do
|
46
|
+
it "should add the definition to the hash" do
|
47
|
+
subject.class.define(".hello", Hash)
|
48
|
+
expect(subject[".hello"]).to eq Hash
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "::class_matching" do
|
54
|
+
let(:selectors) do
|
55
|
+
{
|
56
|
+
".review" => Object,
|
57
|
+
".card" => Hash
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return the first class that matches the given selectors" do
|
62
|
+
doc = %Q(<html><body>
|
63
|
+
<div class="card review"></div>
|
64
|
+
</body></html>)
|
65
|
+
element = Nokogiri::HTML(doc).css(".card").first
|
66
|
+
expect(subject.class.class_matching(element)).to eq Hash
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with no matching selectors" do
|
70
|
+
it "should raise an exception" do
|
71
|
+
doc = %Q(<html><body>
|
72
|
+
<div class="non"></div>
|
73
|
+
</body></html>)
|
74
|
+
element = Nokogiri::HTML(doc).css(".non").first
|
75
|
+
expect {
|
76
|
+
subject.class.class_matching(element)
|
77
|
+
}.to raise_error(RuntimeError)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "::filter" do
|
83
|
+
let(:selectors) do
|
84
|
+
{ ".review" => Object }
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return an array of selectors that match the given classes" do
|
88
|
+
expect(subject.class.filter(Object)).to eq [".review"]
|
89
|
+
expect(subject.class.filter(Hash)).to eq []
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Microformat do
|
4
|
+
subject { Microformat }
|
5
|
+
|
6
|
+
describe "::parse" do
|
7
|
+
let(:args) { ["one", 2, :three] }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
Microformat::Parser.should_receive(:parse).with(*args).and_return(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should pass args onto the parser" do
|
14
|
+
expect(subject.parse(*args)).to be_true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/support/env.rb
ADDED
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elcamino-microformat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Townsend
|
8
|
+
- Tobias Begalke
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-10-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: simplecov
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
description: Reads Microformats from HTML documents
|
71
|
+
email:
|
72
|
+
- ryan@ryantownsend.co.uk
|
73
|
+
- elcamino@spyz.org
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- ".gitignore"
|
79
|
+
- ".rvmrc"
|
80
|
+
- ".travis.yml"
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- lib/microformat.rb
|
86
|
+
- lib/microformat/attribute.rb
|
87
|
+
- lib/microformat/attribute_definition.rb
|
88
|
+
- lib/microformat/attribute_map.rb
|
89
|
+
- lib/microformat/card.rb
|
90
|
+
- lib/microformat/collection.rb
|
91
|
+
- lib/microformat/format.rb
|
92
|
+
- lib/microformat/parser.rb
|
93
|
+
- lib/microformat/review.rb
|
94
|
+
- lib/microformat/review_aggregate.rb
|
95
|
+
- lib/microformat/selectors.rb
|
96
|
+
- lib/microformat/version.rb
|
97
|
+
- microformat.gemspec
|
98
|
+
- spec/microformat/attribute_definition_spec.rb
|
99
|
+
- spec/microformat/attribute_spec.rb
|
100
|
+
- spec/microformat/collection_spec.rb
|
101
|
+
- spec/microformat/format_spec.rb
|
102
|
+
- spec/microformat/parser_spec.rb
|
103
|
+
- spec/microformat/selectors_spec.rb
|
104
|
+
- spec/microformat_spec.rb
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/support/env.rb
|
107
|
+
homepage: https://github.com/elcamino/microformat
|
108
|
+
licenses: []
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.2.2
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Reads Microformats from HTML documents
|
130
|
+
test_files:
|
131
|
+
- spec/microformat/attribute_definition_spec.rb
|
132
|
+
- spec/microformat/attribute_spec.rb
|
133
|
+
- spec/microformat/collection_spec.rb
|
134
|
+
- spec/microformat/format_spec.rb
|
135
|
+
- spec/microformat/parser_spec.rb
|
136
|
+
- spec/microformat/selectors_spec.rb
|
137
|
+
- spec/microformat_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
- spec/support/env.rb
|