document_builder 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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