dash-bees 0.19 → 0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Gemfile +1 -1
- data/dash-bees.gemspec +2 -1
- data/lib/dash-fu/bee.rb +6 -6
- data/lib/dash-fu/bees/feed.rb +104 -0
- data/lib/dash-fu/bees/feed.yml +7 -0
- data/lib/dash-fu/bees/github.rb +0 -8
- data/lib/dash-fu/bees/github_issues.rb +0 -9
- data/test/cassettes/feed.yml +83 -0
- data/test/feed_test.rb +132 -0
- data/test/helpers/source.rb +2 -2
- data/test/test.log +76 -0
- metadata +24 -7
data/CHANGELOG
CHANGED
data/Gemfile
CHANGED
data/dash-bees.gemspec
CHANGED
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
|
19
19
|
spec.required_ruby_version = '>= 1.8.7'
|
20
20
|
spec.add_dependency "activesupport"
|
21
|
+
spec.add_dependency "i18n"
|
21
22
|
spec.add_dependency "json"
|
22
23
|
spec.add_dependency "nokogiri"
|
23
24
|
spec.add_dependency "rack"
|
24
|
-
spec.add_dependency "
|
25
|
+
spec.add_dependency "sanitize"
|
25
26
|
end
|
data/lib/dash-fu/bee.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require "active_support"
|
2
1
|
require "json"
|
3
2
|
require "net/http"
|
4
|
-
require "rack"
|
5
3
|
require "uri"
|
4
|
+
require "open-uri"
|
5
|
+
require "rack"
|
6
6
|
|
7
7
|
# See http://dash-fu.com
|
8
8
|
module DashFu
|
@@ -10,7 +10,7 @@ module DashFu
|
|
10
10
|
# The README covers it all.
|
11
11
|
module Bee
|
12
12
|
|
13
|
-
VERSION = "0.
|
13
|
+
VERSION = "0.20"
|
14
14
|
|
15
15
|
class << self
|
16
16
|
attr_accessor :logger
|
@@ -146,15 +146,15 @@ module DashFu
|
|
146
146
|
# three arguments: status code, response body and response headers. The
|
147
147
|
# block may be called asynchronoulsy.
|
148
148
|
def get(path, headers = {}, &block)
|
149
|
-
response = @http.request(get_request(path, headers))
|
150
|
-
yield response.code, response.body, {}
|
149
|
+
response = @http.request(get_request(path, headers || {}))
|
150
|
+
yield response.code.to_i, response.body, {}
|
151
151
|
end
|
152
152
|
|
153
153
|
# Make a GET request and yield response to the block. If the response
|
154
154
|
# status is 200 the second argument is the response JSON object. The block
|
155
155
|
# may be called asynchronously.
|
156
156
|
def get_json(path, headers = {}, &block)
|
157
|
-
response = @http.request(get_request(path, headers))
|
157
|
+
response = @http.request(get_request(path, headers || {}))
|
158
158
|
if Net::HTTPOK === response
|
159
159
|
json = JSON.parse(response.body) rescue nil
|
160
160
|
if json
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "sanitize"
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module DashFu::Bee
|
5
|
+
# Track Web feed (Atom or RSS).
|
6
|
+
class Feed
|
7
|
+
include DashFu::Bee
|
8
|
+
|
9
|
+
def setup(source, params)
|
10
|
+
source["url"] = params["url"].strip
|
11
|
+
source["source.name"] = "Web feed"
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate(source)
|
15
|
+
uri = URI.parse(source["url"]) rescue nil
|
16
|
+
raise "Not a valid URL" unless uri && uri.absolute?
|
17
|
+
raise "Only HTTP/S URLs supported" unless uri.scheme == "http" || uri.scheme == "https"
|
18
|
+
begin
|
19
|
+
uri.open read_timeout: 3, redirect: true do |io|
|
20
|
+
code = io.status.first
|
21
|
+
raise "Cannot read this feed, got status code #{code}" unless code == "200"
|
22
|
+
feed = (Nokogiri::XML(io.read)>"feed").first
|
23
|
+
source["title"] = get_text(feed>"title").strip
|
24
|
+
source["source.name"] = source["title"] if source["title"].length > 2
|
25
|
+
permalink = (feed>"link[rel=alternate]").first
|
26
|
+
source["permalink"] = permalink["href"] if permalink
|
27
|
+
source["logo"] = (feed>"logo").text
|
28
|
+
end
|
29
|
+
rescue
|
30
|
+
raise "Cannot read this feed: is it down for you or just for us?"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(source, callback)
|
35
|
+
uri = URI.parse(source["url"])
|
36
|
+
session uri.host, uri.port do |http|
|
37
|
+
headers = { username: uri.user, password: uri.password } unless uri.user.blank? && uri.password.blank?
|
38
|
+
http.get uri.request_uri, headers do |status, body|
|
39
|
+
begin
|
40
|
+
case status
|
41
|
+
when 200
|
42
|
+
feed = (Nokogiri::XML(body)>"feed").first
|
43
|
+
updated = Time.iso8601((feed>"updated").text) rescue Time.now
|
44
|
+
if source["updated"].nil? || updated > source["updated"]
|
45
|
+
(feed>"entry").each do |entry|
|
46
|
+
published = Time.iso8601((entry>"published").text) rescue Time.now
|
47
|
+
break unless source["updated"].nil? || updated >= published
|
48
|
+
if author = (entry>"author").first
|
49
|
+
person = { fullname: (author>"name").text, email: (author>"email").text,
|
50
|
+
identities: (author>"uri").map(&:text) }
|
51
|
+
end
|
52
|
+
title = get_text(entry>"title")
|
53
|
+
url = (entry>"link[rel=alternate]").first["href"] rescue nil
|
54
|
+
if content = get_html(entry.css("summary,content"))
|
55
|
+
html = "posted <a href=\"#{h url}\">#{h title}</a>:\n<blockquote>#{content}</blockquote>"
|
56
|
+
else
|
57
|
+
html = "posted a link <a href=\"#{h url}\">#{h title}</a>"
|
58
|
+
end
|
59
|
+
callback.activity! uid: (entry>"id").text, url: url, html: html, timestamp: published, person: person
|
60
|
+
end
|
61
|
+
end
|
62
|
+
source["updated"] = updated
|
63
|
+
when 401
|
64
|
+
callback.error! "You are not authorized to access this feed"
|
65
|
+
when 404
|
66
|
+
callback.error! "Could not find the feed #{source["url"]}"
|
67
|
+
else
|
68
|
+
callback.error! "Last request didn't go as expected, trying again later"
|
69
|
+
end
|
70
|
+
rescue
|
71
|
+
logger.error $!
|
72
|
+
callback.error! "Last request didn't go as expected, trying again later"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def meta(source)
|
79
|
+
meta = []
|
80
|
+
meta << { title: "Source", text: source["title"], url: source["permalink"] }
|
81
|
+
meta
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_text(elements)
|
85
|
+
element = elements.first
|
86
|
+
case element["type"]
|
87
|
+
when "html" ; Nokogiri::HTML(element.text).text.strip
|
88
|
+
when "xhtml", "text", nil ; element.text.strip
|
89
|
+
else ""
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_html(elements)
|
94
|
+
element = elements.first
|
95
|
+
return unless element
|
96
|
+
case element["type"]
|
97
|
+
when "html" ; Sanitize.clean(element.text, Sanitize::Config::BASIC).strip
|
98
|
+
when "xhtml" ; Sanitize.clean(element.to_xhtml, Sanitize::Config::BASIC).strip
|
99
|
+
when "text"; element.text.strip
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/dash-fu/bees/github.rb
CHANGED
@@ -92,13 +92,5 @@ module DashFu::Bee
|
|
92
92
|
meta
|
93
93
|
end
|
94
94
|
|
95
|
-
protected
|
96
|
-
|
97
|
-
def http_request(http, source, path)
|
98
|
-
get = Net::HTTP::Get.new(path.gsub(":repo", URI.escape(source["repo"])).gsub(":branch", URI.escape(source["branch"])))
|
99
|
-
get.basic_auth "#{source["username"]}/token", source["api_token"] unless source["username"].blank? && source["api_token"].blank?
|
100
|
-
http.request(get)
|
101
|
-
end
|
102
|
-
|
103
95
|
end
|
104
96
|
end
|
@@ -78,14 +78,5 @@ closed <a href="#{url}">issue #{issue["number"]}</a> on #{source["repo"]}:
|
|
78
78
|
[ { title: "On GitHub", url: "http://github.com/#{source["repo"]}/issues" } ]
|
79
79
|
end
|
80
80
|
|
81
|
-
protected
|
82
|
-
|
83
|
-
def http_request(http, source, state)
|
84
|
-
path = "/api/v2/json/issues/list/#{URI.escape source["repo"]}/#{state}"
|
85
|
-
get = Net::HTTP::Get.new(path)
|
86
|
-
get.basic_auth "#{source["username"]}/token", source["api_token"] unless source["username"].blank? && source["api_token"].blank?
|
87
|
-
http.request(get)
|
88
|
-
end
|
89
|
-
|
90
81
|
end
|
91
82
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :get
|
5
|
+
uri: http://example.org:80/feed.xml
|
6
|
+
response: !ruby/struct:VCR::Response
|
7
|
+
status: !ruby/struct:VCR::ResponseStatus
|
8
|
+
code: 200
|
9
|
+
message: OK
|
10
|
+
body: |-
|
11
|
+
<?xml version="1.0" encoding="utf-8"?>
|
12
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
13
|
+
<title type="text">dive into mark</title>
|
14
|
+
<subtitle type="html">
|
15
|
+
A <em>lot</em> of effort
|
16
|
+
went into making this effortless
|
17
|
+
</subtitle>
|
18
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
19
|
+
<id>tag:example.org,2003:3</id>
|
20
|
+
<link rel="alternate" type="text/html"
|
21
|
+
hreflang="en" href="http://example.org/"/>
|
22
|
+
<link rel="self" type="application/atom+xml"
|
23
|
+
href="http://example.org/feed.atom"/>
|
24
|
+
<rights>Copyright (c) 2003, Mark Pilgrim</rights>
|
25
|
+
<generator uri="http://www.example.com/" version="1.0">
|
26
|
+
Example Toolkit
|
27
|
+
</generator>
|
28
|
+
<entry>
|
29
|
+
<title>Atom draft-07 snapshot</title>
|
30
|
+
<link rel="alternate" type="text/html"
|
31
|
+
href="http://example.org/2005/04/02/atom"/>
|
32
|
+
<link rel="enclosure" type="audio/mpeg" length="1337"
|
33
|
+
href="http://example.org/audio/ph34r_my_podcast.mp3"/>
|
34
|
+
<id>tag:example.org,2003:3.2397</id>
|
35
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
36
|
+
<published>2003-12-13T08:29:29-04:00</published>
|
37
|
+
<author>
|
38
|
+
<name>Mark Pilgrim</name>
|
39
|
+
<uri>http://example.org/</uri>
|
40
|
+
<email>f8dy@example.com</email>
|
41
|
+
</author>
|
42
|
+
<contributor>
|
43
|
+
<name>Sam Ruby</name>
|
44
|
+
</contributor>
|
45
|
+
<contributor>
|
46
|
+
<name>Joe Gregorio</name>
|
47
|
+
</contributor>
|
48
|
+
<content type="xhtml" xml:lang="en"
|
49
|
+
xml:base="http://diveintomark.org/">
|
50
|
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
51
|
+
<p><i>[Update: The Atom draft is finished.]</i></p>
|
52
|
+
</div>
|
53
|
+
</content>
|
54
|
+
</entry>
|
55
|
+
</feed>
|
56
|
+
- !ruby/struct:VCR::HTTPInteraction
|
57
|
+
request: !ruby/struct:VCR::Request
|
58
|
+
method: :get
|
59
|
+
uri: http://example.org:80/summary.xml
|
60
|
+
response: !ruby/struct:VCR::Response
|
61
|
+
status: !ruby/struct:VCR::ResponseStatus
|
62
|
+
code: 200
|
63
|
+
message: OK
|
64
|
+
body: |-
|
65
|
+
<?xml version="1.0" encoding="utf-8"?>
|
66
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
67
|
+
<title type="text">dive into mark</title>
|
68
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
69
|
+
<entry>
|
70
|
+
<title>Atom draft-07 snapshot</title>
|
71
|
+
<id>tag:example.org,2003:3.2397</id>
|
72
|
+
<published>2003-12-13T08:29:29-04:00</published>
|
73
|
+
<link rel="alternate" type="text/html"
|
74
|
+
href="http://example.org/2005/04/02/atom"/>
|
75
|
+
<summary type="html"><q>Quickly stated</></summary>
|
76
|
+
<content type="xhtml" xml:lang="en"
|
77
|
+
xml:base="http://diveintomark.org/">
|
78
|
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
79
|
+
<p><i>[Update: The Atom draft is finished.]</i></p>
|
80
|
+
</div>
|
81
|
+
</content>
|
82
|
+
</entry>
|
83
|
+
</feed>
|
data/test/feed_test.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative "setup"
|
2
|
+
|
3
|
+
test DashFu::Bee::Feed do
|
4
|
+
context "setup" do
|
5
|
+
subject { source.setup "url"=>"http://example.org/feed.xml" }
|
6
|
+
end
|
7
|
+
|
8
|
+
context "validation" do
|
9
|
+
should "fail if URL is invalid" do
|
10
|
+
assert_raises(RuntimeError) { source.setup("url"=>"/feed.xml") }
|
11
|
+
end
|
12
|
+
|
13
|
+
should "fail if URL is not HTTP" do
|
14
|
+
assert_raises(RuntimeError) { source.setup("url"=>"ftp://example.org/feed.xml") }
|
15
|
+
end
|
16
|
+
|
17
|
+
should "fail if URL is not accessible" do
|
18
|
+
stub_request(:get, "http://example.org/feed.xml").to_timeout
|
19
|
+
assert_raises(RuntimeError) { source.setup("url"=>"http://example.org/feed.xml") }
|
20
|
+
end
|
21
|
+
|
22
|
+
should "fail if status is not 200" do
|
23
|
+
stub_request(:get, "http://example.org/feed.xml").to_return status: 400
|
24
|
+
assert_raises(RuntimeError) { source.setup("url"=>"http://example.org/feed.xml") }
|
25
|
+
end
|
26
|
+
|
27
|
+
should "fail if document is not a feed" do
|
28
|
+
stub_request(:get, "http://example.org/feed.xml").to_return body: { not: "feed" }.to_json
|
29
|
+
assert_raises(RuntimeError) { source.setup("url"=>"http://example.org/feed.xml") }
|
30
|
+
end
|
31
|
+
|
32
|
+
should "set source name from feed title" do
|
33
|
+
stub_request(:get, "http://example.org/feed.xml").to_return body: { title: "The Awesome Feed" }.to_xml(root: "feed")
|
34
|
+
source.setup "url"=>"http://example.org/feed.xml"
|
35
|
+
assert_equal "The Awesome Feed", source.name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "update" do
|
40
|
+
setup { source.setup "url"=>"http://example.org/feed.xml" }
|
41
|
+
|
42
|
+
should "handle 401" do
|
43
|
+
stub_request(:get, interactions.first.uri).to_return :status=>404
|
44
|
+
source.update
|
45
|
+
assert_equal "Could not find the feed http://example.org/feed.xml", source.last_error
|
46
|
+
end
|
47
|
+
|
48
|
+
should "handle 401" do
|
49
|
+
stub_request(:get, interactions.first.uri).to_return :status=>401
|
50
|
+
source.update
|
51
|
+
assert_equal "You are not authorized to access this feed", source.last_error
|
52
|
+
end
|
53
|
+
|
54
|
+
should "handle other error" do
|
55
|
+
stub_request(:get, interactions.first.uri).to_return :status=>500
|
56
|
+
source.update
|
57
|
+
assert_equal "Last request didn't go as expected, trying again later", source.last_error
|
58
|
+
end
|
59
|
+
|
60
|
+
should "handle invlid document entity" do
|
61
|
+
stub_request(:get, interactions.first.uri).to_return :body=>"Not a feed"
|
62
|
+
source.update
|
63
|
+
assert_equal "Last request didn't go as expected, trying again later", source.last_error
|
64
|
+
end
|
65
|
+
|
66
|
+
context "activity" do
|
67
|
+
setup { source.update }
|
68
|
+
subject { source.activity }
|
69
|
+
|
70
|
+
should "capture entry id" do
|
71
|
+
assert_equal "tag:example.org,2003:3.2397", subject.uid
|
72
|
+
end
|
73
|
+
|
74
|
+
should "capture published date" do
|
75
|
+
assert_equal Time.parse("2003-12-13T08:29:29-04:00"), subject.timestamp
|
76
|
+
end
|
77
|
+
|
78
|
+
should "capture URL" do
|
79
|
+
assert_equal "http://example.org/2005/04/02/atom", subject.url
|
80
|
+
end
|
81
|
+
|
82
|
+
should "capture title and content" do
|
83
|
+
assert_equal <<-HTML.strip, subject.html
|
84
|
+
posted <a href=\"http://example.org/2005/04/02/atom\">Atom draft-07 snapshot</a>:
|
85
|
+
<blockquote><p><i>[Update: The Atom draft is finished.]</i></p></blockquote>
|
86
|
+
HTML
|
87
|
+
end
|
88
|
+
|
89
|
+
context "person" do
|
90
|
+
subject { source.activity.person }
|
91
|
+
|
92
|
+
should "capture full name" do
|
93
|
+
assert_equal "Mark Pilgrim", subject.fullname
|
94
|
+
end
|
95
|
+
|
96
|
+
should "capture email" do
|
97
|
+
assert_equal "f8dy@example.com", subject.email
|
98
|
+
end
|
99
|
+
|
100
|
+
should "capture identity" do
|
101
|
+
assert_contains subject.identities, "http://example.org/"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
context "with summary" do
|
108
|
+
setup do
|
109
|
+
source.setup "url"=>"http://example.org/summary.xml"
|
110
|
+
source.update
|
111
|
+
end
|
112
|
+
subject { source.activity }
|
113
|
+
|
114
|
+
should "capture title and summary" do
|
115
|
+
assert_equal <<-HTML.strip, subject.html
|
116
|
+
posted <a href=\"http://example.org/2005/04/02/atom\">Atom draft-07 snapshot</a>:
|
117
|
+
<blockquote><q>Quickly stated</q></blockquote>
|
118
|
+
HTML
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
context "meta" do
|
125
|
+
setup { source.setup "url"=>"http://example.org/feed.xml" }
|
126
|
+
subject { source.meta }
|
127
|
+
|
128
|
+
should "link to site" do
|
129
|
+
assert_contains subject, :title=>"Source", :text=>"dive into mark", :url=>"http://example.org/"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/test/helpers/source.rb
CHANGED
@@ -16,17 +16,17 @@ class Source
|
|
16
16
|
# setup { source.setup "gem_name"=>"vanity" }
|
17
17
|
def setup(params = {})
|
18
18
|
bee.setup state, params
|
19
|
+
bee.validate state
|
19
20
|
self.name = state.delete("source.name")
|
20
21
|
@metric = Metric.new(:name=>name, :columns=>state.delete("metric.columns"), :totals=>!!state.delete("metric.totals")) if state["metric.columns"]
|
21
22
|
validate
|
22
23
|
end
|
23
24
|
|
24
25
|
def validate
|
26
|
+
metric.validate if metric
|
25
27
|
raise "Must be named" if name.blank?
|
26
28
|
raise "Name must be 3 characters of longer" if name.length < 3
|
27
29
|
raise "State fields can only use alphanumeric/underscore in their names" unless state.keys.all? { |k| k =~ /^\w+$/ }
|
28
|
-
bee.validate state
|
29
|
-
metric.validate if metric
|
30
30
|
end
|
31
31
|
|
32
32
|
def valid?
|
data/test/test.log
CHANGED
@@ -932,3 +932,79 @@ RubyGems: 200
|
|
932
932
|
RubyGems: 500
|
933
933
|
RubyGems: 200
|
934
934
|
RubyGems: 500
|
935
|
+
#<Timeout::Error: execution expired>
|
936
|
+
#<NameError: undefined local variable or method `body' for #<DashFu::Bee::Feed:0x00000101b4f670>>
|
937
|
+
#<OpenURI::HTTPError: 400 >
|
938
|
+
#<WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: GET http://example.org/feed.xml with headers {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}>
|
939
|
+
#<Timeout::Error: execution expired>
|
940
|
+
#<NameError: undefined local variable or method `body' for #<DashFu::Bee::Feed:0x000001014b6430>>
|
941
|
+
#<OpenURI::HTTPError: 400 >
|
942
|
+
#<WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: GET http://example.org/feed.xml with headers {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}>
|
943
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x000001015d9650>>
|
944
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x00000101727188>>
|
945
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x00000100e870c8>>
|
946
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x000001013110f8>>
|
947
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x0000010114e1f8>>
|
948
|
+
#<NameError: undefined local variable or method `io' for #<DashFu::Bee::Feed:0x00000101577a90>>
|
949
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
950
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
951
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
952
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
953
|
+
#<NameError: uninitialized constant DashFu::Bee::Rack>
|
954
|
+
#<NameError: uninitialized constant DashFu::Bee::Rack>
|
955
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
956
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
957
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
958
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
959
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
960
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
961
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
962
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
963
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
964
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
965
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
966
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
967
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
968
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
969
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
970
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
971
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
972
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
973
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
974
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
975
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
976
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
977
|
+
#<NoMethodError: undefined method `[]' for nil:NilClass>
|
978
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
979
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
980
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
981
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
982
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
983
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
984
|
+
#<NameError: uninitialized constant DashFu::Bee::Feed::Sanitize>
|
985
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
986
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
987
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
988
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
989
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
990
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
991
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
992
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
993
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
994
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
995
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
996
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
997
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
998
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
999
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
1000
|
+
#<Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: ./content:summary>
|
1001
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1002
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1003
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1004
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1005
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1006
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1007
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1008
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1009
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
1010
|
+
#<NoMethodError: undefined method `namespaces' for nil:NilClass>
|
metadata
CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
version: "0.
|
7
|
+
- 20
|
8
|
+
version: "0.20"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Assaf Arkin
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
type: :runtime
|
31
31
|
version_requirements: *id001
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: i18n
|
34
34
|
prerelease: false
|
35
35
|
requirement: &id002 !ruby/object:Gem::Requirement
|
36
36
|
none: false
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
type: :runtime
|
44
44
|
version_requirements: *id002
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
|
-
name:
|
46
|
+
name: json
|
47
47
|
prerelease: false
|
48
48
|
requirement: &id003 !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
type: :runtime
|
57
57
|
version_requirements: *id003
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
59
|
+
name: nokogiri
|
60
60
|
prerelease: false
|
61
61
|
requirement: &id004 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
@@ -69,7 +69,7 @@ dependencies:
|
|
69
69
|
type: :runtime
|
70
70
|
version_requirements: *id004
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
|
-
name:
|
72
|
+
name: rack
|
73
73
|
prerelease: false
|
74
74
|
requirement: &id005 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
@@ -81,6 +81,19 @@ dependencies:
|
|
81
81
|
version: "0"
|
82
82
|
type: :runtime
|
83
83
|
version_requirements: *id005
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: sanitize
|
86
|
+
prerelease: false
|
87
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
type: :runtime
|
96
|
+
version_requirements: *id006
|
84
97
|
description:
|
85
98
|
email: assaf@labnotes.org
|
86
99
|
executables: []
|
@@ -94,6 +107,8 @@ files:
|
|
94
107
|
- lib/dash-fu/bee.rb
|
95
108
|
- lib/dash-fu/bees/backtweets.rb
|
96
109
|
- lib/dash-fu/bees/backtweets.yml
|
110
|
+
- lib/dash-fu/bees/feed.rb
|
111
|
+
- lib/dash-fu/bees/feed.yml
|
97
112
|
- lib/dash-fu/bees/github.rb
|
98
113
|
- lib/dash-fu/bees/github.yml
|
99
114
|
- lib/dash-fu/bees/github_issues.rb
|
@@ -103,9 +118,11 @@ files:
|
|
103
118
|
- test/api_keys.yml
|
104
119
|
- test/backtweets_test.rb
|
105
120
|
- test/cassettes/backtweets.yml
|
121
|
+
- test/cassettes/feed.yml
|
106
122
|
- test/cassettes/github.yml
|
107
123
|
- test/cassettes/github_issues.yml
|
108
124
|
- test/cassettes/ruby_gems.yml
|
125
|
+
- test/feed_test.rb
|
109
126
|
- test/github_issues_test.rb
|
110
127
|
- test/github_test.rb
|
111
128
|
- test/helpers/activity.rb
|
@@ -129,7 +146,7 @@ licenses: []
|
|
129
146
|
post_install_message:
|
130
147
|
rdoc_options:
|
131
148
|
- --title
|
132
|
-
- DashFu::Bee 0.
|
149
|
+
- DashFu::Bee 0.20
|
133
150
|
- --main
|
134
151
|
- README.rdoc
|
135
152
|
- --webcvs
|