document_builder 0.1.1

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTc3MWYxYWFhYWQwOWI4MjUzOGRhMGE3MGRlNWI0MWExNzk0MDk4NA==
5
+ data.tar.gz: !binary |-
6
+ NDM3MGRkYzNiMWEzMmEyNDYxYjg5MmE5Y2ViZjMzN2Y0NGFiZmYyZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YjJhZjQwYjk3ZWQ1NzQ3ZjY2ZTI5ZWUzOWQxYmE1YmVmNTQ4ODc1MDljOGJh
10
+ YzhmMTAwZTQ4MGUzMjI0MWRiZGUwZmU4ZjgyZDhiODkyNjM1NmVlODZjYWRl
11
+ MTZmZDU1NTNjY2NhMWZmNmM1MjFkMzBmNjliZTg2M2MzZDljNDM=
12
+ data.tar.gz: !binary |-
13
+ MzIyMTJlN2E1NjBhNDUyYjQ0MjdhY2YxYjljNzhmNTNkMWE5OWZmZjViMzcz
14
+ ODA5NDQ5N2FhNWE5Y2M1ZTA2YWU0ZTA4YzY2MmE5ZDM4Mjg0MjI4YjY5MGZh
15
+ YmM3ODNlZTZjYTk0YjI1YjJjNTY4M2IwNDhjYTRhZGU5MGY5Yjg=
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ deploy:
5
+ provider: rubygems
6
+ api_key:
7
+ secure: KLDtpoSEkumzNlaVuzyQUcrFdgMQcLSuGvG5F3yZptijDfFQ4dnQG3MkpdgPuJdxu7J5FZssaFaNDPfb9sgP5pYRcayW4iX3VzKJ5kfsSMYkoU/Yj8PENUGRyK0PjZjJIIeWOPwWg0ZgSBzW9f55Frvv3RBevLHH2c5flHAM0u0=
8
+ gem: document_builder
9
+ on:
10
+ tags: true
11
+ repo: bullfight/document_builder
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in document_builder.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Patrick Schmitz
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,129 @@
1
+ # DocumentBuilder
2
+
3
+ [![Build Status](https://travis-ci.org/bullfight/document_builder.svg?branch=master)](https://travis-ci.org/bullfight/document_builder)
4
+
5
+ This is a small set of modules for building up xpath based document attributes
6
+ from a nokogir document object.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'document_builder'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install document_builder
23
+
24
+ ## Usage
25
+
26
+ ### Documents can be built using the Model and Collection modules as seen in the
27
+ following example
28
+
29
+ ```ruby
30
+ module Document
31
+ class Category
32
+ include DocumentBuilder::Model
33
+ xpath 'category'
34
+ attribute :domain, 'domain', DocumentBuilder::ElementAttribute
35
+ attribute :nicename, 'nicename', DocumentBuilder::ElementAttribute
36
+ attribute :body, nil, DocumentBuilder::ChildAttribute
37
+ end
38
+
39
+ class Postmeta
40
+ include DocumentBuilder::Model
41
+ xpath 'postmeta'
42
+ attribute :key, "wp:meta_key"
43
+ attribute :value, "wp:meta_value", DocumentBuilder::IntegerAttribute
44
+ end
45
+
46
+ class PostmetaCollection
47
+ include DocumentBuilder::Collection
48
+ xpath "item"
49
+ collection :postmeta, "//wp:postmeta", Postmeta
50
+ end
51
+
52
+ class Post
53
+ include DocumentBuilder::Model
54
+ xpath "item"
55
+ attribute :title
56
+ attribute :link
57
+ attribute :pub_date, "pubDate", DocumentBuilder::TimeAttribute
58
+ attribute :creator, "dc:creator"
59
+ attribute :content, "content:encoded"
60
+ attribute :excerpt, "excerpt:encoded"
61
+ attribute :id, "wp:post_id", DocumentBuilder::IntegerAttribute
62
+ attribute :published_at, 'wp:post_date_gmt', DocumentBuilder::TimeAttribute
63
+ attribute :comment_status, "wp:comment_status"
64
+ attribute :ping_status, "wp:ping_status"
65
+ attribute :name, 'wp:post_name'
66
+ attribute :status, "wp:status"
67
+ attribute :parent, "wp:post_parent", DocumentBuilder::IntegerAttribute
68
+ attribute :menu_order, "wp:menu_order", DocumentBuilder::IntegerAttribute
69
+ attribute :type, "wp:post_type"
70
+ attribute :is_sticky, "wp:is_sticky", DocumentBuilder::IntegerAttribute
71
+ attribute :category, "category", Category
72
+ attribute :postmetas, 'item', PostmetaCollection
73
+ end
74
+ end
75
+
76
+ ### Using Model Objects
77
+ ```
78
+
79
+ ```ruby
80
+ # Read an xml file
81
+ url = "https://raw.githubusercontent.com/bullfight/wrxer/master/spec/fixtures/wrx.xml"
82
+ uri = URI.parse(url)
83
+
84
+ uri.open do |file|
85
+ document = Nokogiri::XML(file.read).xpath('//channel').at_xpath('item')}
86
+ end
87
+
88
+ post = Document::Post.call(document)
89
+
90
+ => #<Wrxer::Post:0x3fd4799693ac> Attributes: {
91
+ "title": "Welcome To Wrxer News.",
92
+ "link": "https://wrxernews.wordpress.com/2007/11/17/welcome-to-wrxer-news/",
93
+ "pub_date": "2007-11-17 21:30:51 +0000",
94
+ "creator": "wrxernews",
95
+ "content": "Welcome to <strong>Wrxer News</strong> - The most up-to-date and reliable source for Wrxer news.",
96
+ "excerpt": "Excerpt Text",
97
+ "id": 3,
98
+ "published_at": "2007-11-17 21:30:51 -0800",
99
+ "comment_status": "open",
100
+ "ping_status": "open",
101
+ "name": "welcome-to-wrxer-news",
102
+ "status": "publish",
103
+ "parent": 0,
104
+ "menu_order": 0,
105
+ "type": "post",
106
+ "is_sticky": 0,
107
+ "category": {
108
+ "domain": "category",
109
+ "nicename": "wrxer-news",
110
+ "body": "Wrxer News"
111
+ },
112
+ "postmetas": {
113
+ "data": "#<Enumerator::Lazy:0x007fa8f315a970>"
114
+ },
115
+ "comments": {
116
+ "data": "#<Enumerator::Lazy:0x007fa8f315a3f8>"
117
+ }
118
+ }
119
+ post.title
120
+ => "Welcome To Wrxer News."
121
+ ```
122
+
123
+ ## Contributing
124
+
125
+ 1. Fork it ( https://github.com/[my-github-username]/document_builder/fork )
126
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
127
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
128
+ 4. Push to the branch (`git push origin my-new-feature`)
129
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'document_builder/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "document_builder"
8
+ spec.version = DocumentBuilder::VERSION
9
+ spec.authors = ["Patrick Schmitz"]
10
+ spec.email = ["p.schmitz@gmail.com"]
11
+ spec.summary = %q{A document builder for nokogiri documents.}
12
+ spec.description = %q{This is a small set of modules for building up xpath based document attributes from a nokogir document object.}
13
+ spec.homepage = "https://github.com/bullfight/document_builder"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "nokogiri", "~> 1.6.6"
24
+ spec.add_development_dependency "rspec", "~> 3.2.0"
25
+ spec.add_development_dependency "pry"
26
+ end
@@ -0,0 +1,7 @@
1
+ module DocumentBuilder
2
+ class Attribute < Struct.new(:name, :xpath, :coercion)
3
+ def call(document, params = {})
4
+ coercion.call(document, { xpath: xpath })
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,71 @@
1
+ module DocumentBuilder
2
+ module Coercion
3
+ module ClassMethods
4
+ def xpath(value)
5
+ @xpath = value
6
+ end
7
+
8
+ def call(document, params = {})
9
+ root = @xpath || params[:xpath]
10
+ unless document.name == root
11
+ document = document.at_xpath(root)
12
+ end
13
+
14
+ document.nil? ? nil : self.coerce(document)
15
+ end
16
+
17
+ def coerce(document)
18
+ self.new(document)
19
+ end
20
+ end
21
+
22
+ def self.included(base)
23
+ base.extend(ClassMethods)
24
+ end
25
+ end
26
+
27
+ class TextAttribute
28
+ include Coercion
29
+ def self.coerce(document)
30
+ document.text
31
+ end
32
+ end
33
+
34
+ class IntegerAttribute
35
+ include Coercion
36
+ def self.coerce(document)
37
+ Integer(document.text)
38
+ end
39
+ end
40
+
41
+ class TimeAttribute
42
+ include Coercion
43
+ def self.coerce(document)
44
+ Time.parse(document.text)
45
+ end
46
+ end
47
+
48
+ class ElementAttribute
49
+ include Coercion
50
+ def self.call(document, params = {})
51
+ element = document.attributes[params[:xpath].to_s]
52
+ element.nil? ? nil : self.coerce(element)
53
+ end
54
+
55
+ def self.coerce(document)
56
+ document.value
57
+ end
58
+ end
59
+
60
+ class ChildAttribute
61
+ include Coercion
62
+ def self.call(document, params = {})
63
+ child = document.children
64
+ child.empty? ? nil : self.coerce(child)
65
+ end
66
+
67
+ def self.coerce(document)
68
+ document.text
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,55 @@
1
+ module DocumentBuilder
2
+ module Collection
3
+ module ClassMethods
4
+ def call(document, params = {})
5
+ root = @xpath || params[:xpath]
6
+ unless document.name == root
7
+ document = document.xpath(root)
8
+ end
9
+
10
+ document.nil? ? nil : self.coerce(document)
11
+ end
12
+
13
+ def collection(value, xpath, parser)
14
+ @collection = Attribute.new(value, xpath, parser)
15
+ end
16
+
17
+ def inherited(subclass)
18
+ subclass.instance_variable_set(:@collection, @collection)
19
+ super
20
+ end
21
+ end
22
+
23
+ def self.included(base)
24
+ base.extend(ClassMethods)
25
+ base.class_eval do
26
+ include Model
27
+ include Enumerable
28
+ end
29
+ end
30
+
31
+ def collection
32
+ self.class.instance_variable_get(:@collection)
33
+ end
34
+
35
+ def each(&block)
36
+ document.xpath(collection.xpath).each do |item|
37
+ block.call(
38
+ collection.call(item)
39
+ )
40
+ end
41
+ end
42
+
43
+ def data
44
+ lazy
45
+ end
46
+
47
+ def inspect
48
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}> { data: #{data} } }"
49
+ end
50
+
51
+ def to_hash
52
+ { data: data }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,62 @@
1
+ module DocumentBuilder
2
+ module Model
3
+ module ClassMethods
4
+ def attribute(name, xpath = nil, coercion = TextAttribute)
5
+ @attributes ||= []
6
+ @attributes << Attribute.new(name, xpath || name.to_s, coercion)
7
+ end
8
+
9
+ def inherited(subclass)
10
+ subclass.instance_variable_set(:@attributes, @attributes)
11
+ super
12
+ end
13
+ end
14
+
15
+ def self.included(base)
16
+ base.extend(ClassMethods)
17
+ base.class_eval do
18
+ include Coercion
19
+
20
+ attr_reader :document
21
+ end
22
+ end
23
+
24
+ def initialize(document)
25
+ @document = document
26
+ end
27
+
28
+ def attributes
29
+ self.class.instance_variable_get(:@attributes)
30
+ end
31
+
32
+ def [](key)
33
+ attributes.select { |item| item.name == key.to_sym}.first.call(document)
34
+ end
35
+
36
+ def method_missing(name, *args)
37
+ attributes.select { |item| item.name == name }.first.call(document)
38
+ rescue NoMethodError => e
39
+ raise NoMethodError.new("undefined method '#{name}' for #{self.class}")
40
+ end
41
+
42
+ def to_s(*args)
43
+ JSON.pretty_generate(to_hash)
44
+ end
45
+
46
+ def inspect
47
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}> Attributes: " + JSON.pretty_generate(to_hash)
48
+ end
49
+
50
+ def to_json(*args)
51
+ JSON.generate(to_hash)
52
+ end
53
+
54
+ def to_hash
55
+ attributes.inject({}) do |acc, (key, value)|
56
+ value = key.call(document)
57
+ acc[key.name] = value.respond_to?(:to_hash) ? value.to_hash : value
58
+ acc
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module DocumentBuilder
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require "document_builder/version"
2
+
3
+ require 'time'
4
+ require 'json'
5
+
6
+ require 'document_builder/coercion'
7
+ require 'document_builder/attribute'
8
+ require 'document_builder/model'
9
+ require 'document_builder/collection'
10
+
11
+ module DocumentBuilder
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe DocumentBuilder do
4
+ it 'has a version number' do
5
+ expect(DocumentBuilder::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,45 @@
1
+ module Document
2
+ class Category
3
+ include DocumentBuilder::Model
4
+ xpath 'category'
5
+ attribute :domain, 'domain', DocumentBuilder::ElementAttribute
6
+ attribute :nicename, 'nicename', DocumentBuilder::ElementAttribute
7
+ attribute :body, nil, DocumentBuilder::ChildAttribute
8
+ end
9
+
10
+ class Postmeta
11
+ include DocumentBuilder::Model
12
+ xpath 'postmeta'
13
+ attribute :key, "wp:meta_key"
14
+ attribute :value, "wp:meta_value", DocumentBuilder::IntegerAttribute
15
+ end
16
+
17
+ class PostmetaCollection
18
+ include DocumentBuilder::Collection
19
+ xpath "item"
20
+ collection :postmeta, "//wp:postmeta", Postmeta
21
+ end
22
+
23
+ class Post
24
+ include DocumentBuilder::Model
25
+ xpath "item"
26
+ attribute :title
27
+ attribute :link
28
+ attribute :pub_date, "pubDate", DocumentBuilder::TimeAttribute
29
+ attribute :creator, "dc:creator"
30
+ attribute :content, "content:encoded"
31
+ attribute :excerpt, "excerpt:encoded"
32
+ attribute :id, "wp:post_id", DocumentBuilder::IntegerAttribute
33
+ attribute :published_at, 'wp:post_date_gmt', DocumentBuilder::TimeAttribute
34
+ attribute :comment_status, "wp:comment_status"
35
+ attribute :ping_status, "wp:ping_status"
36
+ attribute :name, 'wp:post_name'
37
+ attribute :status, "wp:status"
38
+ attribute :parent, "wp:post_parent", DocumentBuilder::IntegerAttribute
39
+ attribute :menu_order, "wp:menu_order", DocumentBuilder::IntegerAttribute
40
+ attribute :type, "wp:post_type"
41
+ attribute :is_sticky, "wp:is_sticky", DocumentBuilder::IntegerAttribute
42
+ attribute :category, "category", Category
43
+ attribute :postmetas, 'item', PostmetaCollection
44
+ end
45
+ end
@@ -0,0 +1,155 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ This is a WordPress eXtended RSS file generated by WordPress as an export of your site.
4
+ It contains information about your site's posts, pages, comments, categories, and other content.
5
+ You may use this file to transfer that content from one site to another.
6
+ This file is not intended to serve as a complete backup of your site.
7
+
8
+ To import this information into a WordPress site follow these steps:
9
+ 1. Log in to that site as an administrator.
10
+ 2. Go to Tools: Import in the WordPress admin panel.
11
+ 3. Install the "WordPress" importer from the list.
12
+ 4. Activate & Run Importer.
13
+ 5. Upload this file using the form provided on that page.
14
+ 6. You will first be asked to map the authors in this export file to users
15
+ on the site. For each author, you may choose to map to an
16
+ existing user on the site or to create a new user.
17
+ 7. WordPress will then import each of the posts, pages, comments, categories, etc.
18
+ contained in this file into your site.
19
+ -->
20
+ <!-- generator="WordPress.com" created="2015-03-24 21:18"-->
21
+ <rss version="2.0" xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wp="http://wordpress.org/export/1.2/">
22
+ <channel>
23
+ <title>Wrxer News</title>
24
+ <link>https://wrxernews.wordpress.com</link>
25
+ <description>The Most Reliable Source For Wrxer News Since 2007.</description>
26
+ <pubDate>Tue, 24 Mar 2015 21:18:58 +0000</pubDate>
27
+ <language>en</language>
28
+ <wp:wxr_version>1.2</wp:wxr_version>
29
+ <wp:base_site_url>http://wordpress.com/</wp:base_site_url>
30
+ <wp:base_blog_url>https://wrxernews.wordpress.com</wp:base_blog_url>
31
+ <wp:author>
32
+ <wp:author_login>wrxernews</wp:author_login>
33
+ <wp:author_email>wrxernews@example.com</wp:author_email>
34
+ <wp:author_display_name><![CDATA[Wrx News]]></wp:author_display_name>
35
+ <wp:author_first_name><![CDATA[]]></wp:author_first_name>
36
+ <wp:author_last_name><![CDATA[]]></wp:author_last_name>
37
+ </wp:author>
38
+ <generator>http://wordpress.com/</generator>
39
+ <image>
40
+ <url>https://secure.gravatar.com/blavatar/foobar</url>
41
+ <title> &#187; Wrx News</title>
42
+ <link>https://wrxernews.wordpress.com</link>
43
+ </image>
44
+ <item>
45
+ <title>Missing post_id, post_name, post_date_gmt, and category</title>
46
+ <link>https://wrxernews.wordpress.com/2007/11/17/welcome-to-wrxer-news/</link>
47
+ <pubDate>Sat, 17 Nov 2007 21:30:51 +0000</pubDate>
48
+ <dc:creator>wrxernews</dc:creator>
49
+ <guid isPermaLink="false">http://wrxernews.wordpress.com/2007/11/17/welcome-to-wrxer-news/</guid>
50
+ <description/>
51
+ <content:encoded><![CDATA[Welcome to <strong>Wrx News</strong> - The most up-to-date and reliable source for Wrxer news.]]></content:encoded>
52
+ <excerpt:encoded><![CDATA[Excerpt Text]]></excerpt:encoded>
53
+ <wp:post_date>2007-11-17 15:30:51</wp:post_date>
54
+ <wp:comment_status>open</wp:comment_status>
55
+ <wp:ping_status>open</wp:ping_status>
56
+ <wp:status>publish</wp:status>
57
+ <wp:post_parent>0</wp:post_parent>
58
+ <wp:menu_order>0</wp:menu_order>
59
+ <wp:post_type>post</wp:post_type>
60
+ <wp:post_password/>
61
+ <wp:is_sticky>0</wp:is_sticky>
62
+ <category></category>
63
+ <wp:postmeta>
64
+ <wp:meta_key>_wpas_skip_4017882</wp:meta_key>
65
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
66
+ </wp:postmeta>
67
+ <wp:postmeta>
68
+ <wp:meta_key>_wpas_skip_47065</wp:meta_key>
69
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
70
+ </wp:postmeta>
71
+ <wp:postmeta>
72
+ <wp:meta_key>geo_public</wp:meta_key>
73
+ <wp:meta_value><![CDATA[0]]></wp:meta_value>
74
+ </wp:postmeta>
75
+ <wp:postmeta>
76
+ <wp:meta_key>_edit_last</wp:meta_key>
77
+ <wp:meta_value><![CDATA[2223113]]></wp:meta_value>
78
+ </wp:postmeta>
79
+ <wp:comment>
80
+ <wp:comment_id>2</wp:comment_id>
81
+ <wp:comment_author><![CDATA[Kid Vengeance]]></wp:comment_author>
82
+ <wp:comment_author_email>user@example.com</wp:comment_author_email>
83
+ <wp:comment_author_url>http://www.example.com/foobar</wp:comment_author_url>
84
+ <wp:comment_author_IP>69.245.96.185</wp:comment_author_IP>
85
+ <wp:comment_date>2007-11-18 11:45:26</wp:comment_date>
86
+ <wp:comment_date_gmt>2007-11-18 17:45:26</wp:comment_date_gmt>
87
+ <wp:comment_content><![CDATA[I feel this is going to be a great site! ]]></wp:comment_content>
88
+ <wp:comment_approved>1</wp:comment_approved>
89
+ <wp:comment_type/>
90
+ <wp:comment_parent>0</wp:comment_parent>
91
+ <wp:comment_user_id>0</wp:comment_user_id>
92
+ <wp:commentmeta>
93
+ <wp:meta_key>_elasticsearch_indexed_on</wp:meta_key>
94
+ <wp:meta_value>2007-11-18 17:45:26</wp:meta_value>
95
+ </wp:commentmeta>
96
+ </wp:comment>
97
+ <wp:comment>
98
+ <wp:comment_id>2900</wp:comment_id>
99
+ <wp:comment_author><![CDATA[iSyn4LiFe]]></wp:comment_author>
100
+ <wp:comment_author_email>user2@example.com</wp:comment_author_email>
101
+ <wp:comment_author_url/>
102
+ <wp:comment_author_IP>76.31.208.107</wp:comment_author_IP>
103
+ <wp:comment_date>2008-11-16 10:12:08</wp:comment_date>
104
+ <wp:comment_date_gmt>2008-11-16 17:12:08</wp:comment_date_gmt>
105
+ <wp:comment_content><![CDATA[I agree with Kid, that this is gonna be a great site so yeah good luck with it!!]]></wp:comment_content>
106
+ <wp:comment_approved>1</wp:comment_approved>
107
+ <wp:comment_type/>
108
+ <wp:comment_parent>0</wp:comment_parent>
109
+ <wp:comment_user_id>0</wp:comment_user_id>
110
+ <wp:commentmeta>
111
+ <wp:meta_key>_elasticsearch_indexed_on</wp:meta_key>
112
+ <wp:meta_value>2008-11-16 17:12:08</wp:meta_value>
113
+ </wp:commentmeta>
114
+ </wp:comment>
115
+ </item>
116
+ <item>
117
+ <title>Missing Category</title>
118
+ <link>https://wrxernews.wordpress.com/2007/11/17/wrxer-on-the-radio/</link>
119
+ <pubDate>Sat, 17 Nov 2007 21:33:08 +0000</pubDate>
120
+ <dc:creator>wrxernews</dc:creator>
121
+ <guid isPermaLink="false">http://wrxernews.wordpress.com/2007/11/17/wrxer-on-the-radio/</guid>
122
+ <description/>
123
+ <content:encoded><![CDATA[On November 19th, <a href="http://www.example.com/wrxer" target="_blank">wrxer</a> will be featured guests on the radio.]]></content:encoded>
124
+ <excerpt:encoded><![CDATA[]]></excerpt:encoded>
125
+ <wp:post_id>5</wp:post_id>
126
+ <wp:post_date>2007-11-17 15:33:08</wp:post_date>
127
+ <wp:post_date_gmt>2007-11-17 21:33:08</wp:post_date_gmt>
128
+ <wp:comment_status>open</wp:comment_status>
129
+ <wp:ping_status>open</wp:ping_status>
130
+ <wp:post_name>wrxer-on-the-radio</wp:post_name>
131
+ <wp:status>publish</wp:status>
132
+ <wp:post_parent>0</wp:post_parent>
133
+ <wp:menu_order>0</wp:menu_order>
134
+ <wp:post_type>post</wp:post_type>
135
+ <wp:post_password/>
136
+ <wp:is_sticky>0</wp:is_sticky>
137
+ <wp:postmeta>
138
+ <wp:meta_key>_edit_last</wp:meta_key>
139
+ <wp:meta_value><![CDATA[2223113]]></wp:meta_value>
140
+ </wp:postmeta>
141
+ <wp:postmeta>
142
+ <wp:meta_key>geo_public</wp:meta_key>
143
+ <wp:meta_value><![CDATA[0]]></wp:meta_value>
144
+ </wp:postmeta>
145
+ <wp:postmeta>
146
+ <wp:meta_key>_wpas_skip_4017882</wp:meta_key>
147
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
148
+ </wp:postmeta>
149
+ <wp:postmeta>
150
+ <wp:meta_key>_wpas_skip_47065</wp:meta_key>
151
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
152
+ </wp:postmeta>
153
+ </item>
154
+ </channel>
155
+ </rss>
@@ -0,0 +1,159 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ This is a WordPress eXtended RSS file generated by WordPress as an export of your site.
4
+ It contains information about your site's posts, pages, comments, categories, and other content.
5
+ You may use this file to transfer that content from one site to another.
6
+ This file is not intended to serve as a complete backup of your site.
7
+
8
+ To import this information into a WordPress site follow these steps:
9
+ 1. Log in to that site as an administrator.
10
+ 2. Go to Tools: Import in the WordPress admin panel.
11
+ 3. Install the "WordPress" importer from the list.
12
+ 4. Activate & Run Importer.
13
+ 5. Upload this file using the form provided on that page.
14
+ 6. You will first be asked to map the authors in this export file to users
15
+ on the site. For each author, you may choose to map to an
16
+ existing user on the site or to create a new user.
17
+ 7. WordPress will then import each of the posts, pages, comments, categories, etc.
18
+ contained in this file into your site.
19
+ -->
20
+ <!-- generator="WordPress.com" created="2015-03-24 21:18"-->
21
+ <rss version="2.0" xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wp="http://wordpress.org/export/1.2/">
22
+ <channel>
23
+ <title>Wrxer News</title>
24
+ <link>https://wrxernews.wordpress.com</link>
25
+ <description>The Most Reliable Source For Wrxer News Since 2007.</description>
26
+ <pubDate>Tue, 24 Mar 2015 21:18:58 +0000</pubDate>
27
+ <language>en</language>
28
+ <wp:wxr_version>1.2</wp:wxr_version>
29
+ <wp:base_site_url>http://wordpress.com/</wp:base_site_url>
30
+ <wp:base_blog_url>https://wrxernews.wordpress.com</wp:base_blog_url>
31
+ <wp:author>
32
+ <wp:author_login>wrxernews</wp:author_login>
33
+ <wp:author_email>wrxernews@example.com</wp:author_email>
34
+ <wp:author_display_name><![CDATA[Wrxer News]]></wp:author_display_name>
35
+ <wp:author_first_name><![CDATA[]]></wp:author_first_name>
36
+ <wp:author_last_name><![CDATA[]]></wp:author_last_name>
37
+ </wp:author>
38
+ <generator>http://wordpress.com/</generator>
39
+ <image>
40
+ <url>https://secure.gravatar.com/blavatar/foobar</url>
41
+ <title> &#187; Wrxer News</title>
42
+ <link>https://wrxernews.wordpress.com</link>
43
+ </image>
44
+ <item>
45
+ <title>Welcome To Wrxer News.</title>
46
+ <link>https://wrxernews.wordpress.com/2007/11/17/welcome-to-wrxer-news/</link>
47
+ <pubDate>Sat, 17 Nov 2007 21:30:51 +0000</pubDate>
48
+ <dc:creator>wrxernews</dc:creator>
49
+ <guid isPermaLink="false">http://wrxernews.wordpress.com/2007/11/17/welcome-to-wrxer-news/</guid>
50
+ <description/>
51
+ <content:encoded><![CDATA[Welcome to <strong>Wrxer News</strong> - The most up-to-date and reliable source for Wrxer news.]]></content:encoded>
52
+ <excerpt:encoded><![CDATA[Excerpt Text]]></excerpt:encoded>
53
+ <wp:post_id>3</wp:post_id>
54
+ <wp:post_date>2007-11-17 15:30:51</wp:post_date>
55
+ <wp:post_date_gmt>2007-11-17 21:30:51</wp:post_date_gmt>
56
+ <wp:comment_status>open</wp:comment_status>
57
+ <wp:ping_status>open</wp:ping_status>
58
+ <wp:post_name>welcome-to-wrxer-news</wp:post_name>
59
+ <wp:status>publish</wp:status>
60
+ <wp:post_parent>0</wp:post_parent>
61
+ <wp:menu_order>0</wp:menu_order>
62
+ <wp:post_type>post</wp:post_type>
63
+ <wp:post_password/>
64
+ <wp:is_sticky>0</wp:is_sticky>
65
+ <category domain="category" nicename="wrxer-news"><![CDATA[Wrxer News]]></category>
66
+ <wp:postmeta>
67
+ <wp:meta_key>_wpas_skip_4017882</wp:meta_key>
68
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
69
+ </wp:postmeta>
70
+ <wp:postmeta>
71
+ <wp:meta_key>_wpas_skip_47065</wp:meta_key>
72
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
73
+ </wp:postmeta>
74
+ <wp:postmeta>
75
+ <wp:meta_key>geo_public</wp:meta_key>
76
+ <wp:meta_value><![CDATA[0]]></wp:meta_value>
77
+ </wp:postmeta>
78
+ <wp:postmeta>
79
+ <wp:meta_key>_edit_last</wp:meta_key>
80
+ <wp:meta_value><![CDATA[2223113]]></wp:meta_value>
81
+ </wp:postmeta>
82
+ <wp:comment>
83
+ <wp:comment_id>2</wp:comment_id>
84
+ <wp:comment_author><![CDATA[Kid Vengeance]]></wp:comment_author>
85
+ <wp:comment_author_email>user@example.com</wp:comment_author_email>
86
+ <wp:comment_author_url>http://www.example.com/foobar</wp:comment_author_url>
87
+ <wp:comment_author_IP>69.245.96.185</wp:comment_author_IP>
88
+ <wp:comment_date>2007-11-18 11:45:26</wp:comment_date>
89
+ <wp:comment_date_gmt>2007-11-18 17:45:26</wp:comment_date_gmt>
90
+ <wp:comment_content><![CDATA[I feel this is going to be a great site! ]]></wp:comment_content>
91
+ <wp:comment_approved>1</wp:comment_approved>
92
+ <wp:comment_type/>
93
+ <wp:comment_parent>0</wp:comment_parent>
94
+ <wp:comment_user_id>0</wp:comment_user_id>
95
+ <wp:commentmeta>
96
+ <wp:meta_key>_elasticsearch_indexed_on</wp:meta_key>
97
+ <wp:meta_value>2007-11-18 17:45:26</wp:meta_value>
98
+ </wp:commentmeta>
99
+ </wp:comment>
100
+ <wp:comment>
101
+ <wp:comment_id>2900</wp:comment_id>
102
+ <wp:comment_author><![CDATA[iSyn4LiFe]]></wp:comment_author>
103
+ <wp:comment_author_email>user2@example.com</wp:comment_author_email>
104
+ <wp:comment_author_url/>
105
+ <wp:comment_author_IP>76.31.208.107</wp:comment_author_IP>
106
+ <wp:comment_date>2008-11-16 10:12:08</wp:comment_date>
107
+ <wp:comment_date_gmt>2008-11-16 17:12:08</wp:comment_date_gmt>
108
+ <wp:comment_content><![CDATA[I agree with Kid, that this is gonna be a great site so yeah good luck with it!!]]></wp:comment_content>
109
+ <wp:comment_approved>1</wp:comment_approved>
110
+ <wp:comment_type/>
111
+ <wp:comment_parent>0</wp:comment_parent>
112
+ <wp:comment_user_id>0</wp:comment_user_id>
113
+ <wp:commentmeta>
114
+ <wp:meta_key>_elasticsearch_indexed_on</wp:meta_key>
115
+ <wp:meta_value>2008-11-16 17:12:08</wp:meta_value>
116
+ </wp:commentmeta>
117
+ </wp:comment>
118
+ </item>
119
+ <item>
120
+ <title>Wrxer on the Radio</title>
121
+ <link>https://wrxernews.wordpress.com/2007/11/17/wrxer-on-the-radio/</link>
122
+ <pubDate>Sat, 17 Nov 2007 21:33:08 +0000</pubDate>
123
+ <dc:creator>wrxernews</dc:creator>
124
+ <guid isPermaLink="false">http://wrxernews.wordpress.com/2007/11/17/wrxer-on-the-radio/</guid>
125
+ <description/>
126
+ <content:encoded><![CDATA[On November 19th, <a href="http://www.example.com/wrxer" target="_blank">wrxer</a> will be featured guests on the radio.]]></content:encoded>
127
+ <excerpt:encoded><![CDATA[]]></excerpt:encoded>
128
+ <wp:post_id>5</wp:post_id>
129
+ <wp:post_date>2007-11-17 15:33:08</wp:post_date>
130
+ <wp:post_date_gmt>2007-11-17 21:33:08</wp:post_date_gmt>
131
+ <wp:comment_status>open</wp:comment_status>
132
+ <wp:ping_status>open</wp:ping_status>
133
+ <wp:post_name>wrxer-on-the-radio</wp:post_name>
134
+ <wp:status>publish</wp:status>
135
+ <wp:post_parent>0</wp:post_parent>
136
+ <wp:menu_order>0</wp:menu_order>
137
+ <wp:post_type>post</wp:post_type>
138
+ <wp:post_password/>
139
+ <wp:is_sticky>0</wp:is_sticky>
140
+ <category domain="category" nicename="radio"><![CDATA[Radio]]></category>
141
+ <wp:postmeta>
142
+ <wp:meta_key>_edit_last</wp:meta_key>
143
+ <wp:meta_value><![CDATA[2223113]]></wp:meta_value>
144
+ </wp:postmeta>
145
+ <wp:postmeta>
146
+ <wp:meta_key>geo_public</wp:meta_key>
147
+ <wp:meta_value><![CDATA[0]]></wp:meta_value>
148
+ </wp:postmeta>
149
+ <wp:postmeta>
150
+ <wp:meta_key>_wpas_skip_4017882</wp:meta_key>
151
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
152
+ </wp:postmeta>
153
+ <wp:postmeta>
154
+ <wp:meta_key>_wpas_skip_47065</wp:meta_key>
155
+ <wp:meta_value><![CDATA[1]]></wp:meta_value>
156
+ </wp:postmeta>
157
+ </item>
158
+ </channel>
159
+ </rss>
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'nokogiri'
3
+ require 'fixtures/document'
4
+
5
+ describe Document::Post do
6
+ context 'valid document' do
7
+ let(:filename) { fixture('wrx.xml') }
8
+ let(:document) { Nokogiri::XML(filename.read).xpath('//channel').at_xpath('item')}
9
+ subject { described_class.call(document) }
10
+
11
+ it 'has an id' do
12
+ expect(subject.id).to eq 3
13
+ end
14
+
15
+ it 'has a title' do
16
+ expect(subject.title).to eq "Welcome To Wrxer News."
17
+ end
18
+
19
+ it 'has a content' do
20
+ expect(subject.content).to match /Welcome to/
21
+ end
22
+
23
+ it 'has an excerpt' do
24
+ expect(subject.excerpt).to eq "Excerpt Text"
25
+ end
26
+
27
+ it 'has a slug' do
28
+ expect(subject.name).to eq "welcome-to-wrxer-news"
29
+ end
30
+
31
+ it 'has a post date' do
32
+ expect(subject.published_at).to eq Time.parse("2007-11-17 21:30:51")
33
+ end
34
+
35
+ it 'has a category' do
36
+ expect(subject.category).to be_a Document::Category
37
+ end
38
+
39
+ it 'has is_sticky' do
40
+ expect(subject.is_sticky).to eq 0
41
+ end
42
+
43
+ it 'has postmetas' do
44
+ expect(subject.postmetas.first).to be_a Document::Postmeta
45
+ end
46
+
47
+ it 'does not have a not foo' do
48
+ expect { subject.foo }.to raise_error(
49
+ NoMethodError, "undefined method 'foo' for Document::Post")
50
+ end
51
+ end
52
+
53
+ context "nil attribute case" do
54
+ let(:filename) { fixture('missing_fields.xml') }
55
+ let(:document) { Nokogiri::XML(filename.read).xpath('//channel').at_xpath('item')}
56
+ subject { described_class.call(document) }
57
+
58
+ it 'returns nil for nil integer' do
59
+ expect(subject.id).to eq nil
60
+ end
61
+
62
+ it 'returns nil for text' do
63
+ expect(subject.name).to eq nil
64
+ end
65
+
66
+ it 'returns nil for time' do
67
+ expect(subject.published_at).to eq nil
68
+ end
69
+ end
70
+
71
+ context "for missing node" do
72
+ let(:filename) { fixture('missing_fields.xml') }
73
+ let(:document) { Nokogiri::XML(filename.read).xpath('//channel').xpath('item')[1]}
74
+ subject { described_class.new(document) }
75
+
76
+ it 'returns nil for category' do
77
+ expect(subject.category).to eq nil
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'document_builder'
3
+ require 'pry'
4
+
5
+ def fixture_path
6
+ File.expand_path("../fixtures", __FILE__)
7
+ end
8
+
9
+ def fixture(file)
10
+ File.new(fixture_path + '/' + file)
11
+ end
12
+
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: document_builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Patrick Schmitz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.6.6
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 3.2.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 3.2.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: This is a small set of modules for building up xpath based document attributes
84
+ from a nokogir document object.
85
+ email:
86
+ - p.schmitz@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .travis.yml
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - document_builder.gemspec
99
+ - lib/document_builder.rb
100
+ - lib/document_builder/attribute.rb
101
+ - lib/document_builder/coercion.rb
102
+ - lib/document_builder/collection.rb
103
+ - lib/document_builder/model.rb
104
+ - lib/document_builder/version.rb
105
+ - spec/document_builder_spec.rb
106
+ - spec/fixtures/document.rb
107
+ - spec/fixtures/missing_fields.xml
108
+ - spec/fixtures/wrx.xml
109
+ - spec/integration_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://github.com/bullfight/document_builder
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.5
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: A document builder for nokogiri documents.
135
+ test_files:
136
+ - spec/document_builder_spec.rb
137
+ - spec/fixtures/document.rb
138
+ - spec/fixtures/missing_fields.xml
139
+ - spec/fixtures/wrx.xml
140
+ - spec/integration_spec.rb
141
+ - spec/spec_helper.rb