pluto 0.8.3 → 0.8.4
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.
- data/Manifest.txt +7 -1
- data/README.md +36 -35
- data/lib/pluto/activerecord.rb +18 -0
- data/lib/pluto/cli/main.rb +57 -3
- data/lib/pluto/cli/opts.rb +13 -2
- data/lib/pluto/fetcher.rb +60 -2
- data/lib/pluto/models/action.rb +12 -0
- data/lib/pluto/models/feed.rb +51 -0
- data/lib/pluto/models/item.rb +35 -0
- data/lib/pluto/models/site.rb +12 -0
- data/lib/pluto/models/subscription.rb +14 -0
- data/lib/pluto/models/utils.rb +43 -0
- data/lib/pluto/refresher.rb +5 -59
- data/lib/pluto/schema.rb +10 -3
- data/lib/pluto/subscriber.rb +3 -8
- data/lib/pluto/template_helpers.rb +32 -1
- data/lib/pluto/version.rb +1 -1
- data/lib/pluto.rb +15 -2
- metadata +27 -21
- data/lib/pluto/models.rb +0 -94
data/Manifest.txt
CHANGED
@@ -5,6 +5,7 @@ Rakefile
|
|
5
5
|
bin/pluto
|
6
6
|
config/pluto.index.yml
|
7
7
|
lib/pluto.rb
|
8
|
+
lib/pluto/activerecord.rb
|
8
9
|
lib/pluto/cli/main.rb
|
9
10
|
lib/pluto/cli/opts.rb
|
10
11
|
lib/pluto/connecter.rb
|
@@ -13,7 +14,12 @@ lib/pluto/formatter.rb
|
|
13
14
|
lib/pluto/installer.rb
|
14
15
|
lib/pluto/lister.rb
|
15
16
|
lib/pluto/manifest_helpers.rb
|
16
|
-
lib/pluto/models.rb
|
17
|
+
lib/pluto/models/action.rb
|
18
|
+
lib/pluto/models/feed.rb
|
19
|
+
lib/pluto/models/item.rb
|
20
|
+
lib/pluto/models/site.rb
|
21
|
+
lib/pluto/models/subscription.rb
|
22
|
+
lib/pluto/models/utils.rb
|
17
23
|
lib/pluto/refresher.rb
|
18
24
|
lib/pluto/schema.rb
|
19
25
|
lib/pluto/subscriber.rb
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ from published web feeds.
|
|
7
7
|
* bugs :: [github.com/feedreader/pluto/issues](https://github.com/feedreader/pluto/issues)
|
8
8
|
* gem :: [rubygems.org/gems/pluto](https://rubygems.org/gems/pluto)
|
9
9
|
* rdoc :: [rubydoc.info/gems/pluto](http://rubydoc.info/gems/pluto)
|
10
|
-
|
10
|
+
* forum :: [groups.google.com/group/feedreader](http://groups.google.com/group/feedreader)
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
@@ -50,13 +50,13 @@ GLOBAL OPTIONS
|
|
50
50
|
--help - Show this message
|
51
51
|
|
52
52
|
COMMANDS
|
53
|
-
build, b
|
54
|
-
install, i
|
55
|
-
list, ls, l
|
56
|
-
|
57
|
-
merge, m
|
58
|
-
about, a
|
59
|
-
help
|
53
|
+
build, b - Build planet
|
54
|
+
install, i - Install template pack
|
55
|
+
list, ls, l - List installed template packs
|
56
|
+
update, up, u - Update planet feeds
|
57
|
+
merge, m - Merge planet template pack
|
58
|
+
about, a - (Debug) Show more version info
|
59
|
+
help - Shows a list of commands or help for one command
|
60
60
|
~~~~
|
61
61
|
|
62
62
|
|
@@ -109,18 +109,18 @@ EXAMPLE
|
|
109
109
|
~~~
|
110
110
|
|
111
111
|
|
112
|
-
#### `
|
112
|
+
#### `update` Command
|
113
113
|
|
114
114
|
~~~
|
115
115
|
NAME
|
116
|
-
|
116
|
+
update - Update planet feeds
|
117
117
|
|
118
118
|
SYNOPSIS
|
119
|
-
pluto [global options]
|
119
|
+
pluto [global options] update FILE
|
120
120
|
|
121
121
|
EXAMPLE
|
122
|
-
pluto
|
123
|
-
pluto
|
122
|
+
pluto update ruby.yml
|
123
|
+
pluto u ruby
|
124
124
|
~~~
|
125
125
|
|
126
126
|
|
@@ -144,7 +144,6 @@ EXAMPLE
|
|
144
144
|
|
145
145
|
|
146
146
|
|
147
|
-
|
148
147
|
### Planet Configuration Sample
|
149
148
|
|
150
149
|
`ruby.ini`:
|
@@ -153,19 +152,19 @@ EXAMPLE
|
|
153
152
|
title = Planet Ruby
|
154
153
|
|
155
154
|
[rubyflow]
|
156
|
-
title
|
157
|
-
|
158
|
-
|
155
|
+
title = Ruby Flow
|
156
|
+
link = http://rubyflow.com
|
157
|
+
feed = http://feeds.feedburner.com/Rubyflow?format=xml
|
159
158
|
|
160
159
|
[rubyonrails]
|
161
|
-
title
|
162
|
-
|
163
|
-
|
160
|
+
title = Ruby on Rails Blog
|
161
|
+
link = http://weblog.rubyonrails.org
|
162
|
+
feed = http://weblog.rubyonrails.org/feed/atom.xml
|
164
163
|
|
165
164
|
[viennarb]
|
166
|
-
title
|
167
|
-
|
168
|
-
|
165
|
+
title = vienna.rb Blog
|
166
|
+
link = http://vienna-rb.at
|
167
|
+
feed = http://vienna-rb.at/atom.xml
|
169
168
|
```
|
170
169
|
|
171
170
|
or `ruby.yml`:
|
@@ -175,25 +174,28 @@ title: Planet Ruby
|
|
175
174
|
|
176
175
|
|
177
176
|
rubyflow:
|
178
|
-
title:
|
179
|
-
|
180
|
-
|
177
|
+
title: Ruby Flow
|
178
|
+
link: http://rubyflow.com
|
179
|
+
feed: http://feeds.feedburner.com/Rubyflow?format=xml
|
181
180
|
|
182
181
|
rubyonrails:
|
183
|
-
title:
|
184
|
-
|
185
|
-
|
182
|
+
title: Ruby on Rails Blog
|
183
|
+
link: http://weblog.rubyonrails.org
|
184
|
+
feed: http://weblog.rubyonrails.org/feed/atom.xml
|
186
185
|
|
187
186
|
viennarb:
|
188
|
-
title:
|
189
|
-
|
190
|
-
|
187
|
+
title: vienna.rb Blog
|
188
|
+
link: http://vienna-rb.at
|
189
|
+
feed: http://vienna-rb.at/atom.xml
|
191
190
|
```
|
192
191
|
|
193
192
|
For more samples, see [`nytimes.yml`](https://github.com/feedreader/pluto.samples/blob/master/nytimes.yml),
|
194
193
|
[`js.yml`](https://github.com/feedreader/pluto.samples/blob/master/js.yml),
|
195
|
-
[`dart.yml`](https://github.com/feedreader/pluto.samples/blob/master/dart.yml)
|
196
|
-
|
194
|
+
[`dart.yml`](https://github.com/feedreader/pluto.samples/blob/master/dart.yml),
|
195
|
+
[`haskell.yml`](https://github.com/feedreader/pluto.samples/blob/master/haskell.yml),
|
196
|
+
[`viennarb.yml`](https://github.com/feedreader/pluto.samples/blob/master/viennarb.yml),
|
197
|
+
[`beer.yml`](https://github.com/feedreader/pluto.samples/blob/master/beer.yml),
|
198
|
+
[`football.yml`](https://github.com/feedreader/pluto.samples/blob/master/football.yml).
|
197
199
|
|
198
200
|
## Install
|
199
201
|
|
@@ -232,6 +234,5 @@ Use it as you please with no restrictions whatsoever.
|
|
232
234
|
|
233
235
|
## Questions? Comments?
|
234
236
|
|
235
|
-
Questions? Comments?
|
236
237
|
Send them along to the [Planet Pluto and Friends Forum/Mailing List](http://groups.google.com/group/feedreader).
|
237
238
|
Thanks!
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
module ActiveRecordMethods
|
4
|
+
|
5
|
+
def read_attribute_w_fallbacks( *keys )
|
6
|
+
### todo: use a different name e.g.:
|
7
|
+
## read_attribute_cascade ?? - does anything like this exists already?
|
8
|
+
## why? why not?
|
9
|
+
keys.each do |key|
|
10
|
+
value = read_attribute( key )
|
11
|
+
return value unless value.nil?
|
12
|
+
end
|
13
|
+
value # fallthrough? return latest value (will be nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end # module ActiveRecordMethods
|
18
|
+
end # module Pluto
|
data/lib/pluto/cli/main.rb
CHANGED
@@ -160,6 +160,60 @@ default_value opts.config_path
|
|
160
160
|
flag [:c, :config]
|
161
161
|
|
162
162
|
|
163
|
+
### note: mostly for debugging lets you fetch individual feeds
|
164
|
+
desc 'Fetch feeds'
|
165
|
+
arg_name 'FEED', multiple: true ## todo/fix: check multiple will not print typeo???
|
166
|
+
command [:fetch, :f] do |c|
|
167
|
+
|
168
|
+
c.desc 'Database path'
|
169
|
+
c.arg_name 'PATH'
|
170
|
+
c.default_value opts.db_path
|
171
|
+
c.flag [:d, :dbpath]
|
172
|
+
|
173
|
+
c.desc 'Database name'
|
174
|
+
c.arg_name 'NAME'
|
175
|
+
c.default_value opts.db_name
|
176
|
+
c.flag [:n, :dbname]
|
177
|
+
|
178
|
+
c.action do |g,o,args|
|
179
|
+
logger.debug 'hello from fetch command'
|
180
|
+
|
181
|
+
## turn on debug flag by default; no need to passing --verbose
|
182
|
+
LogUtils::Logger.root.level = :debug
|
183
|
+
opts.verbose = true
|
184
|
+
|
185
|
+
# add dbname as opts property
|
186
|
+
|
187
|
+
#####
|
188
|
+
# todo: add into method for reuse for build/merge/fetch
|
189
|
+
# all use the same code
|
190
|
+
|
191
|
+
db_config = {
|
192
|
+
adapter: 'sqlite3',
|
193
|
+
database: "#{opts.db_path}/#{opts.db_name}"
|
194
|
+
}
|
195
|
+
|
196
|
+
Pluto::Connecter.new.connect!( db_config )
|
197
|
+
|
198
|
+
args.each do |arg|
|
199
|
+
feed_rec = Pluto::Models::Feed.find_by_key!( arg )
|
200
|
+
|
201
|
+
puts "feed_rec:"
|
202
|
+
pp feed_rec
|
203
|
+
|
204
|
+
fetcher = Pluto::Fetcher.new
|
205
|
+
fetcher.debug = true # by default debug is true (only used for debuggin! - save feed to file, etc.)
|
206
|
+
|
207
|
+
feed = fetcher.feed_by_rec( feed_rec )
|
208
|
+
## pp feed
|
209
|
+
end
|
210
|
+
|
211
|
+
puts 'Done.'
|
212
|
+
end
|
213
|
+
end # command fetch
|
214
|
+
|
215
|
+
|
216
|
+
|
163
217
|
## note: same as build (but without step 1) fetch)
|
164
218
|
desc 'Merge planet template pack'
|
165
219
|
arg_name 'FILE', multiple: true ## todo/fix: check multiple will not print typeo???
|
@@ -206,12 +260,12 @@ end # command merge
|
|
206
260
|
|
207
261
|
|
208
262
|
## note: same as build (but without step 2) merge)
|
209
|
-
desc '
|
263
|
+
desc 'Update planet feeds'
|
210
264
|
arg_name 'FILE', multiple: true ## todo/fix: check multiple will not print typeo???
|
211
|
-
command [:
|
265
|
+
command [:update, :up, :u] do |c|
|
212
266
|
|
213
267
|
c.action do |g,o,args|
|
214
|
-
logger.debug 'hello from
|
268
|
+
logger.debug 'hello from update command'
|
215
269
|
|
216
270
|
args = expand_config_args( args ) # add missing .ini|.yml extension if missing or add default config (e.g. pluto.ini)
|
217
271
|
|
data/lib/pluto/cli/opts.rb
CHANGED
@@ -9,13 +9,24 @@ class Opts
|
|
9
9
|
|
10
10
|
def merge_gli_options!( options={} )
|
11
11
|
@verbose = true if options[:verbose] == true
|
12
|
-
|
12
|
+
|
13
|
+
@db_path = options[:dbpath] if options[:dbpath].present?
|
14
|
+
@db_name = options[:dbname] if options[:dbname].present?
|
15
|
+
|
13
16
|
@config_path = options[:config] if options[:config].present?
|
14
17
|
@output_path = options[:output] if options[:output].present?
|
15
|
-
|
18
|
+
|
16
19
|
@manifest = options[:template] if options[:template].present?
|
17
20
|
end
|
18
21
|
|
22
|
+
def db_path
|
23
|
+
@db_path || '.'
|
24
|
+
end
|
25
|
+
|
26
|
+
def db_name
|
27
|
+
@db_name || 'pluto.db'
|
28
|
+
end
|
29
|
+
|
19
30
|
|
20
31
|
def manifest=(value)
|
21
32
|
@manifest = value
|
data/lib/pluto/fetcher.rb
CHANGED
@@ -3,9 +3,67 @@ module Pluto
|
|
3
3
|
|
4
4
|
class Fetcher
|
5
5
|
|
6
|
-
|
7
|
-
# now in refresher
|
6
|
+
include LogUtils::Logging
|
8
7
|
|
8
|
+
def initialize
|
9
|
+
@worker = ::Fetcher::Worker.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug=(value) @debug = value; end
|
13
|
+
def debug?() @debug || false; end
|
14
|
+
|
15
|
+
|
16
|
+
def feed_by_rec( feed_rec )
|
17
|
+
feed_url = feed_rec.feed_url
|
18
|
+
feed_key = feed_rec.key
|
19
|
+
|
20
|
+
feed_xml = fetch_feed( feed_url )
|
21
|
+
|
22
|
+
logger.debug "feed_xml:"
|
23
|
+
logger.debug feed_xml[ 0..300 ] # get first 300 chars
|
24
|
+
|
25
|
+
# if opts.verbose? # also write a copy to disk
|
26
|
+
if debug?
|
27
|
+
logger.debug "saving feed to >./#{feed_key}.xml<..."
|
28
|
+
File.open( "./#{feed_key}.xml", 'w' ) do |f|
|
29
|
+
f.write( feed_xml )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Before parsing feed >#{feed_key}<..."
|
34
|
+
|
35
|
+
### move to feedutils
|
36
|
+
### logger.debug "using stdlib RSS::VERSION #{RSS::VERSION}"
|
37
|
+
|
38
|
+
## fix/todo: check for feed.nil? -> error parsing!!!
|
39
|
+
# or throw exception
|
40
|
+
feed = FeedUtils::Parser.parse( feed_xml )
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def fetch_feed( url )
|
45
|
+
### fix: use worker.get( url ) # check http response code etc.
|
46
|
+
|
47
|
+
xml = @worker.read( url )
|
48
|
+
|
49
|
+
###
|
50
|
+
# NB: Net::HTTP will NOT set encoding UTF-8 etc.
|
51
|
+
# will mostly be ASCII
|
52
|
+
# - try to change encoding to UTF-8 ourselves
|
53
|
+
logger.debug "xml.encoding.name (before): #{xml.encoding.name}"
|
54
|
+
|
55
|
+
#####
|
56
|
+
# NB: ASCII-8BIT == BINARY == Encoding Unknown; Raw Bytes Here
|
57
|
+
|
58
|
+
## NB:
|
59
|
+
# for now "hardcoded" to utf8 - what else can we do?
|
60
|
+
# - note: force_encoding will NOT change the chars only change the assumed encoding w/o translation
|
61
|
+
xml = xml.force_encoding( Encoding::UTF_8 )
|
62
|
+
logger.debug "xml.encoding.name (after): #{xml.encoding.name}"
|
63
|
+
|
64
|
+
xml
|
65
|
+
end
|
66
|
+
|
9
67
|
end # class Fetcher
|
10
68
|
|
11
69
|
end # module Pluto
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pluto
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Feed < ActiveRecord::Base
|
5
|
+
self.table_name = 'feeds'
|
6
|
+
|
7
|
+
include Pluto::ActiveRecordMethods # e.g. read_attribute_w_fallbacks
|
8
|
+
|
9
|
+
has_many :items
|
10
|
+
has_many :subscriptions
|
11
|
+
has_many :sites, :through => :subscriptions
|
12
|
+
|
13
|
+
|
14
|
+
def self.latest
|
15
|
+
# note: order by first non-null datetime field
|
16
|
+
# coalesce - supported by sqlite (yes), postgres (yes)
|
17
|
+
|
18
|
+
# note: if not published_at,touched_at or built_at use hardcoded 1911-01-01 for now
|
19
|
+
## order( "coalesce(published_at,touched_at,built_at,'1911-01-01') desc" )
|
20
|
+
order( "coalesce(latest_published_at,'1911-01-01') desc" )
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def url?() read_attribute(:url).present?; end
|
25
|
+
def title?() read_attribute(:title).present?; end
|
26
|
+
def feed_url?() read_attribute(:feed_url).present?; end
|
27
|
+
|
28
|
+
def url() read_attribute_w_fallbacks( :url, :auto_url ); end
|
29
|
+
def title() read_attribute_w_fallbacks( :title, :auto_title ); end
|
30
|
+
def feed_url() read_attribute_w_fallbacks( :feed_url, :auto_feed_url ); end
|
31
|
+
|
32
|
+
|
33
|
+
def published_at?() read_attribute(:published_at).present?; end
|
34
|
+
def touched_at?() read_attribute(:touched_at).present?; end
|
35
|
+
|
36
|
+
def published_at
|
37
|
+
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
38
|
+
# db backed attribute
|
39
|
+
|
40
|
+
read_attribute_w_fallbacks(
|
41
|
+
:published_at, # try touched_at (aka updated (ATOM))
|
42
|
+
:touched_at, # try build_at (aka lastBuildDate (RSS))
|
43
|
+
:built_at
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class Feed
|
48
|
+
|
49
|
+
|
50
|
+
end # module Models
|
51
|
+
end # module Pluto
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Pluto
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Item < ActiveRecord::Base
|
5
|
+
self.table_name = 'items'
|
6
|
+
|
7
|
+
include Pluto::ActiveRecordMethods # e.g. read_attribute_w_fallbacks
|
8
|
+
|
9
|
+
belongs_to :feed
|
10
|
+
|
11
|
+
def self.latest
|
12
|
+
# note: order by first non-null datetime field
|
13
|
+
# coalesce - supported by sqlite (yes), postgres (yes)
|
14
|
+
|
15
|
+
# note: if not published_at,touched_at or built_at use hardcoded 1911-01-01 for now
|
16
|
+
order( "coalesce(published_at,touched_at,'1911-01-01') desc" )
|
17
|
+
end
|
18
|
+
|
19
|
+
def published_at?() read_attribute(:published_at).present?; end
|
20
|
+
|
21
|
+
def published_at
|
22
|
+
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
23
|
+
# db backed attribute
|
24
|
+
|
25
|
+
read_attribute_w_fallbacks(
|
26
|
+
:published_at,
|
27
|
+
:touched_at # try touched_at (aka updated)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
end # class Item
|
32
|
+
|
33
|
+
|
34
|
+
end # module Models
|
35
|
+
end # module Pluto
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pluto
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class ItemCursor
|
5
|
+
|
6
|
+
def initialize( items )
|
7
|
+
@items = items
|
8
|
+
end
|
9
|
+
|
10
|
+
def each
|
11
|
+
last_published_at = Time.local( 1911, 1, 1 )
|
12
|
+
last_feed_id = -1 ## todo: use feed_key instead of id?? why? why not??
|
13
|
+
|
14
|
+
@items.each do |item|
|
15
|
+
|
16
|
+
item_published_at = item.published_at # cache published_at value ref
|
17
|
+
|
18
|
+
if last_published_at.year == item_published_at.year &&
|
19
|
+
last_published_at.month == item_published_at.month &&
|
20
|
+
last_published_at.day == item_published_at.day
|
21
|
+
new_date = false
|
22
|
+
else
|
23
|
+
new_date = true
|
24
|
+
end
|
25
|
+
|
26
|
+
if last_feed_id == item.feed.id
|
27
|
+
new_feed = false
|
28
|
+
else
|
29
|
+
new_feed = true
|
30
|
+
end
|
31
|
+
|
32
|
+
yield( item, new_date, new_feed )
|
33
|
+
|
34
|
+
last_published_at = item.published_at
|
35
|
+
last_feed_id = item.feed.id
|
36
|
+
end
|
37
|
+
end # method each
|
38
|
+
|
39
|
+
end # class ItemCursor
|
40
|
+
|
41
|
+
|
42
|
+
end # module Models
|
43
|
+
end # module Pluto
|
data/lib/pluto/refresher.rb
CHANGED
@@ -7,54 +7,20 @@ class Refresher
|
|
7
7
|
include Models
|
8
8
|
|
9
9
|
def initialize
|
10
|
-
@worker =
|
11
|
-
end
|
12
|
-
|
13
|
-
attr_reader :worker
|
14
|
-
|
15
|
-
def debug=(value)
|
16
|
-
@debug = value
|
17
|
-
### logger.debug "[Updater] setting debug flag - debug? #{debug?}"
|
18
|
-
end
|
19
|
-
|
20
|
-
def debug?
|
21
|
-
@debug || false
|
22
|
-
end
|
23
|
-
|
24
|
-
def fetch_feed( url )
|
25
|
-
|
26
|
-
### fix: use worker.get( url ) # check http response code etc.
|
27
|
-
|
28
|
-
xml = worker.read( url )
|
29
|
-
|
30
|
-
###
|
31
|
-
# NB: Net::HTTP will NOT set encoding UTF-8 etc.
|
32
|
-
# will mostly be ASCII
|
33
|
-
# - try to change encoding to UTF-8 ourselves
|
34
|
-
logger.debug "xml.encoding.name (before): #{xml.encoding.name}"
|
35
|
-
|
36
|
-
#####
|
37
|
-
# NB: ASCII-8BIT == BINARY == Encoding Unknown; Raw Bytes Here
|
38
|
-
|
39
|
-
## NB:
|
40
|
-
# for now "hardcoded" to utf8 - what else can we do?
|
41
|
-
# - note: force_encoding will NOT change the chars only change the assumed encoding w/o translation
|
42
|
-
xml = xml.force_encoding( Encoding::UTF_8 )
|
43
|
-
logger.debug "xml.encoding.name (after): #{xml.encoding.name}"
|
44
|
-
xml
|
10
|
+
@worker = Fetcher.new
|
45
11
|
end
|
46
12
|
|
13
|
+
def debug=(value) @debug = value; end
|
14
|
+
def debug?() @debug || false; end
|
47
15
|
|
48
16
|
def update_feeds( opts={} )
|
49
17
|
|
50
18
|
if debug?
|
51
19
|
## turn on logging for sql too
|
52
20
|
ActiveRecord::Base.logger = Logger.new( STDOUT )
|
21
|
+
@worker.debug = true # also pass along worker debug flag if set
|
53
22
|
end
|
54
23
|
|
55
|
-
### move to feedutils
|
56
|
-
### logger.debug "using stdlib RSS::VERSION #{RSS::VERSION}"
|
57
|
-
|
58
24
|
# -- log update action
|
59
25
|
Action.create!( title: 'update feeds' )
|
60
26
|
|
@@ -68,27 +34,7 @@ class Refresher
|
|
68
34
|
|
69
35
|
Feed.all.each do |feed_rec|
|
70
36
|
|
71
|
-
|
72
|
-
feed_url = feed_rec.feed_url
|
73
|
-
|
74
|
-
feed_xml = fetch_feed( feed_url )
|
75
|
-
|
76
|
-
logger.debug "feed_xml:"
|
77
|
-
logger.debug feed_xml[ 0..300 ] # get first 300 chars
|
78
|
-
|
79
|
-
# if opts.verbose? # also write a copy to disk
|
80
|
-
if debug?
|
81
|
-
logger.debug "saving feed to >./#{feed_key}.xml<..."
|
82
|
-
File.open( "./#{feed_key}.xml", 'w' ) do |f|
|
83
|
-
f.write( feed_xml )
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
puts "Before parsing feed >#{feed_key}<..."
|
88
|
-
|
89
|
-
## fix/todo: check for feed.nil? -> error parsing!!!
|
90
|
-
# or throw exception
|
91
|
-
feed = FeedUtils::Parser.parse( feed_xml )
|
37
|
+
feed = @worker.feed_by_rec( feed_rec )
|
92
38
|
|
93
39
|
feed_fetched_at = Time.now
|
94
40
|
|
data/lib/pluto/schema.rb
CHANGED
@@ -19,11 +19,18 @@ class CreateDb < ActiveRecord::Migration
|
|
19
19
|
end
|
20
20
|
|
21
21
|
create_table :feeds do |t|
|
22
|
-
t.string :title
|
22
|
+
t.string :title # user supplied titled
|
23
|
+
t.string :auto_title # "fallback" - auto(fill) title from feed
|
24
|
+
|
25
|
+
t.string :url # user supplied site url
|
26
|
+
t.string :auto_url # "fallback" - auto(fill) url from feed
|
27
|
+
|
28
|
+
t.string :feed_url # user supplied feed url
|
29
|
+
t.string :auto_feed_url # "fallback" - auto discovery feed url from (site) url
|
30
|
+
|
23
31
|
t.string :title2 # e.g. subtitle (atom)
|
24
32
|
t.text :summary # e.g. description (rss)
|
25
|
-
|
26
|
-
t.string :feed_url, :null => false
|
33
|
+
|
27
34
|
t.string :generator # feed generator (e.g. wordpress, etc.) from feed
|
28
35
|
|
29
36
|
t.datetime :published_at # from feed published(atom)+ pubDate(rss)
|
data/lib/pluto/subscriber.rb
CHANGED
@@ -6,14 +6,9 @@ class Subscriber
|
|
6
6
|
|
7
7
|
include Models
|
8
8
|
|
9
|
-
def debug=(value)
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def debug?
|
15
|
-
@debug || false
|
16
|
-
end
|
9
|
+
def debug=(value) @debug = value; end
|
10
|
+
def debug?() @debug || false; end
|
11
|
+
|
17
12
|
|
18
13
|
def update_subscriptions( config, opts={} )
|
19
14
|
|
@@ -60,16 +60,47 @@ module TemplateHelper
|
|
60
60
|
end # method whitelist
|
61
61
|
|
62
62
|
|
63
|
+
|
64
|
+
|
65
|
+
## move into own helper module???
|
66
|
+
## - any helper already for easy reuse
|
67
|
+
##
|
68
|
+
# rails style asset tag helpers and friends
|
69
|
+
|
70
|
+
def stylesheet_link_tag( href )
|
71
|
+
href = "#{href}.css" unless href.ends_with( '.css' ) # auto-add .css if not present
|
72
|
+
"<link rel='stylesheet' type='text/css' href='#{href}'>"
|
73
|
+
end
|
74
|
+
|
75
|
+
def image_tag( src, opts={} )
|
76
|
+
attributes = ""
|
77
|
+
opts.each do |key,value|
|
78
|
+
attributes << "#{key}='#{value}' "
|
79
|
+
end
|
80
|
+
"<img src='#{src}' #{attributes}>"
|
81
|
+
end
|
82
|
+
|
83
|
+
def link_to( text, href, opts={} )
|
84
|
+
attributes = ""
|
85
|
+
opts.each do |key,value|
|
86
|
+
attributes << "#{key}='#{value}' "
|
87
|
+
end
|
88
|
+
"<a href='#{href}' #{attributes}>#{text}</a>"
|
89
|
+
end
|
90
|
+
|
91
|
+
|
63
92
|
## change to simple_hypertext or
|
64
93
|
# hypertext_simple or
|
65
94
|
# sanitize ???
|
95
|
+
|
66
96
|
|
97
|
+
|
67
98
|
def textify( hy, opts={} ) # hy -> hypertext
|
68
99
|
## turn into text
|
69
100
|
# todo: add options for
|
70
101
|
# keep links, images, lists (?too), code, codeblocks
|
71
102
|
|
72
|
-
hy = whitelist( hy, [:br, :p, :ul, :ol, :li, :pre, :code], opts )
|
103
|
+
hy = whitelist( hy, [:br, :p, :ul, :ol, :li, :pre, :code, :blockquote, :q, :cite], opts )
|
73
104
|
|
74
105
|
# strip bold
|
75
106
|
# hy = hy.gsub( /<b[^>]*>/, '**' ) # fix: will also swallow bxxx tags - add b space
|
data/lib/pluto/version.rb
CHANGED
data/lib/pluto.rb
CHANGED
@@ -31,7 +31,15 @@ require 'textutils'
|
|
31
31
|
|
32
32
|
require 'pluto/version' # let version always get first
|
33
33
|
require 'pluto/schema'
|
34
|
-
require 'pluto/
|
34
|
+
require 'pluto/activerecord'
|
35
|
+
|
36
|
+
require 'pluto/models/action'
|
37
|
+
require 'pluto/models/feed'
|
38
|
+
require 'pluto/models/item'
|
39
|
+
require 'pluto/models/site'
|
40
|
+
require 'pluto/models/subscription'
|
41
|
+
require 'pluto/models/utils'
|
42
|
+
|
35
43
|
require 'pluto/manifest_helpers'
|
36
44
|
require 'pluto/connecter'
|
37
45
|
|
@@ -52,6 +60,10 @@ module Pluto
|
|
52
60
|
"pluto #{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
53
61
|
end
|
54
62
|
|
63
|
+
def self.generator # convenience alias for banner (matches HTML generator meta tag)
|
64
|
+
banner
|
65
|
+
end
|
66
|
+
|
55
67
|
def self.root
|
56
68
|
"#{File.expand_path( File.dirname(File.dirname(__FILE__)) )}"
|
57
69
|
end
|
@@ -77,8 +89,9 @@ module Pluto
|
|
77
89
|
end # module Pluto
|
78
90
|
|
79
91
|
|
92
|
+
|
80
93
|
######
|
81
|
-
# todo - move to
|
94
|
+
# todo - move to ext/array.rb or similar
|
82
95
|
|
83
96
|
class Array
|
84
97
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pluto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pakman
|
16
|
-
requirement: &
|
16
|
+
requirement: &74627180 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0.5'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *74627180
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: fetcher
|
27
|
-
requirement: &
|
27
|
+
requirement: &74626900 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0.3'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *74626900
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: logutils
|
38
|
-
requirement: &
|
38
|
+
requirement: &74626660 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0.6'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *74626660
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: feedutils
|
49
|
-
requirement: &
|
49
|
+
requirement: &74626360 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.3.2
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *74626360
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: props
|
60
|
-
requirement: &
|
60
|
+
requirement: &74626110 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.0.2
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *74626110
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: textutils
|
71
|
-
requirement: &
|
71
|
+
requirement: &74625810 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 0.6.8
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *74625810
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: gli
|
82
|
-
requirement: &
|
82
|
+
requirement: &74625560 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 2.5.6
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *74625560
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rdoc
|
93
|
-
requirement: &
|
93
|
+
requirement: &74641630 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ~>
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '3.10'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *74641630
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: hoe
|
104
|
-
requirement: &
|
104
|
+
requirement: &74641390 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '3.3'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *74641390
|
113
113
|
description: pluto - Another Planet Generator (Lets You Build Web Pages from Published
|
114
114
|
Web Feeds)
|
115
115
|
email: feedreader@googlegroups.com
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- bin/pluto
|
127
127
|
- config/pluto.index.yml
|
128
128
|
- lib/pluto.rb
|
129
|
+
- lib/pluto/activerecord.rb
|
129
130
|
- lib/pluto/cli/main.rb
|
130
131
|
- lib/pluto/cli/opts.rb
|
131
132
|
- lib/pluto/connecter.rb
|
@@ -134,7 +135,12 @@ files:
|
|
134
135
|
- lib/pluto/installer.rb
|
135
136
|
- lib/pluto/lister.rb
|
136
137
|
- lib/pluto/manifest_helpers.rb
|
137
|
-
- lib/pluto/models.rb
|
138
|
+
- lib/pluto/models/action.rb
|
139
|
+
- lib/pluto/models/feed.rb
|
140
|
+
- lib/pluto/models/item.rb
|
141
|
+
- lib/pluto/models/site.rb
|
142
|
+
- lib/pluto/models/subscription.rb
|
143
|
+
- lib/pluto/models/utils.rb
|
138
144
|
- lib/pluto/refresher.rb
|
139
145
|
- lib/pluto/schema.rb
|
140
146
|
- lib/pluto/subscriber.rb
|
data/lib/pluto/models.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
module Pluto
|
2
|
-
module Models
|
3
|
-
|
4
|
-
class Feed < ActiveRecord::Base
|
5
|
-
self.table_name = 'feeds'
|
6
|
-
|
7
|
-
has_many :items
|
8
|
-
has_many :subscriptions
|
9
|
-
has_many :sites, :through => :subscriptions
|
10
|
-
|
11
|
-
|
12
|
-
def self.latest
|
13
|
-
# note: order by first non-null datetime field
|
14
|
-
# coalesce - supported by sqlite (yes), postgres (yes)
|
15
|
-
|
16
|
-
# note: if not published_at,touched_at or built_at use hardcoded 1999-01-01 for now
|
17
|
-
## order( "coalesce(published_at,touched_at,built_at,'1999-01-01') desc" )
|
18
|
-
order( "coalesce(latest_published_at,'1999-01-01') desc" )
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
def published_at?
|
23
|
-
read_attribute(:published_at).present?
|
24
|
-
end
|
25
|
-
|
26
|
-
def published_at
|
27
|
-
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
28
|
-
# db backed attribute
|
29
|
-
|
30
|
-
if read_attribute(:published_at).present?
|
31
|
-
read_attribute(:published_at)
|
32
|
-
elsif read_attribute(:touched_at).present?
|
33
|
-
## try touched_at (aka updated (ATOM))
|
34
|
-
read_attribute(:touched_at)
|
35
|
-
else ## try build_at (aka lastBuildDate (RSS))
|
36
|
-
read_attribute(:built_at)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end # class Feed
|
41
|
-
|
42
|
-
class Item < ActiveRecord::Base
|
43
|
-
self.table_name = 'items'
|
44
|
-
|
45
|
-
belongs_to :feed
|
46
|
-
|
47
|
-
def self.latest
|
48
|
-
# note: order by first non-null datetime field
|
49
|
-
# coalesce - supported by sqlite (yes), postgres (yes)
|
50
|
-
|
51
|
-
# note: if not published_at,touched_at or built_at use hardcoded 1999-01-01 for now
|
52
|
-
order( "coalesce(published_at,touched_at,'1999-01-01') desc" )
|
53
|
-
end
|
54
|
-
|
55
|
-
def published_at?
|
56
|
-
read_attribute(:published_at).present?
|
57
|
-
end
|
58
|
-
|
59
|
-
def published_at
|
60
|
-
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
61
|
-
# db backed attribute
|
62
|
-
|
63
|
-
if read_attribute(:published_at).present?
|
64
|
-
read_attribute(:published_at)
|
65
|
-
else ## try touched_at (aka updated)
|
66
|
-
read_attribute(:touched_at)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
end # class Item
|
71
|
-
|
72
|
-
|
73
|
-
class Site < ActiveRecord::Base
|
74
|
-
self.table_name = 'sites'
|
75
|
-
|
76
|
-
has_many :subscriptions
|
77
|
-
has_many :feeds, :through => :subscriptions
|
78
|
-
end
|
79
|
-
|
80
|
-
class Subscription < ActiveRecord::Base
|
81
|
-
self.table_name = 'subscriptions'
|
82
|
-
|
83
|
-
belongs_to :site
|
84
|
-
belongs_to :feed
|
85
|
-
end
|
86
|
-
|
87
|
-
class Action < ActiveRecord::Base
|
88
|
-
self.table_name = 'actions'
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
end # module Models
|
94
|
-
end # module Pluto
|