pluto-models 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/HISTORY.md +4 -0
- data/Manifest.txt +30 -0
- data/README.md +82 -0
- data/Rakefile +41 -0
- data/config/pluto.index.yml +23 -0
- data/lib/pluto/activerecord.rb +18 -0
- data/lib/pluto/connecter.rb +96 -0
- data/lib/pluto/fetcher.rb +292 -0
- data/lib/pluto/formatter.rb +81 -0
- data/lib/pluto/installer.rb +58 -0
- data/lib/pluto/lister.rb +42 -0
- data/lib/pluto/manifest_helpers.rb +51 -0
- data/lib/pluto/models.rb +130 -0
- data/lib/pluto/models/activity.rb +8 -0
- data/lib/pluto/models/feed.rb +127 -0
- data/lib/pluto/models/item.rb +73 -0
- data/lib/pluto/models/site.rb +19 -0
- data/lib/pluto/models/subscription.rb +14 -0
- data/lib/pluto/models/utils.rb +47 -0
- data/lib/pluto/refresher.rb +130 -0
- data/lib/pluto/schema.rb +139 -0
- data/lib/pluto/subscriber.rb +102 -0
- data/lib/pluto/tasks/env.rake +25 -0
- data/lib/pluto/tasks/setup.rake +40 -0
- data/lib/pluto/tasks/stats.rake +10 -0
- data/lib/pluto/tasks/update.rake +24 -0
- data/lib/pluto/updater.rb +50 -0
- data/lib/pluto/version.rb +28 -0
- data/test/helper.rb +13 -0
- data/test/test_helpers.rb +22 -0
- metadata +262 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
class Formatter
|
4
|
+
|
5
|
+
include LogUtils::Logging
|
6
|
+
|
7
|
+
include Models
|
8
|
+
include ManifestHelper
|
9
|
+
|
10
|
+
include TextUtils::DateHelper # e.g. lets us use time_ago_in_words
|
11
|
+
include TextUtils::HypertextHelper # e.g. lets us use link_to, strip_tags, sanitize, textify, etc.
|
12
|
+
|
13
|
+
def initialize( opts, config )
|
14
|
+
@opts = opts
|
15
|
+
@config = config
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :opts, :config, :site
|
19
|
+
|
20
|
+
|
21
|
+
def run( arg )
|
22
|
+
### remove - always use make( site_key )
|
23
|
+
## fix: change arg to planet_key or just key or similar
|
24
|
+
# todo: rename run to some less generic - merge/build/etc. ??
|
25
|
+
|
26
|
+
site_key = arg
|
27
|
+
site_key = site_key.downcase.gsub('.ini','').gsub('.yml','') # remove .ini|.yml extension if present
|
28
|
+
|
29
|
+
manifest_name = opts.manifest
|
30
|
+
output_path = opts.output_path
|
31
|
+
|
32
|
+
make_for(site_key, manifest_name, output_path )
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def make_for( site_key, manifest_name, output_path )
|
37
|
+
|
38
|
+
## fix: remove reference to opts
|
39
|
+
## - e.g. now still used for auto-installer
|
40
|
+
|
41
|
+
manifest_name = manifest_name.downcase.gsub('.txt', '' ) # remove .txt if present
|
42
|
+
|
43
|
+
logger.debug "manifest=#{manifest_name}"
|
44
|
+
|
45
|
+
# check for matching manifests
|
46
|
+
manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
|
47
|
+
|
48
|
+
if manifests.empty?
|
49
|
+
|
50
|
+
### try - autodownload
|
51
|
+
puts "*** template pack '#{manifest_name}' not found; trying auto-install..."
|
52
|
+
|
53
|
+
Installer.new( opts ).install( manifest_name )
|
54
|
+
|
55
|
+
### try again
|
56
|
+
|
57
|
+
# check for matching manifests
|
58
|
+
manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
|
59
|
+
|
60
|
+
if manifests.empty?
|
61
|
+
puts "*** error: unknown template pack '#{manifest_name}'; use pluto ls to list installed template packs"
|
62
|
+
exit 2
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
manifestsrc = manifests[0][1]
|
67
|
+
pakpath = output_path
|
68
|
+
|
69
|
+
@site = Site.find_by_key( site_key )
|
70
|
+
if @site.nil?
|
71
|
+
puts "*** warn: no site with key '#{site_key}' found; using untitled site record"
|
72
|
+
@site = Site.new
|
73
|
+
@site.title = 'Planet Untitled'
|
74
|
+
end
|
75
|
+
|
76
|
+
Pakman::Templater.new.merge_pak( manifestsrc, pakpath, binding, site_key )
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class Formatter
|
80
|
+
|
81
|
+
end # module Pluto
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
class Installer
|
4
|
+
|
5
|
+
### fix: remove opts, use config (wrapped!!)
|
6
|
+
|
7
|
+
include LogUtils::Logging
|
8
|
+
|
9
|
+
def initialize( opts )
|
10
|
+
@opts = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :opts
|
14
|
+
|
15
|
+
|
16
|
+
def install( shortcut_or_source )
|
17
|
+
|
18
|
+
logger.debug "fetch >#{shortcut_or_source}<"
|
19
|
+
|
20
|
+
## check for builtin shortcut (assume no / or \)
|
21
|
+
if shortcut_or_source.index( '/' ).nil? && shortcut_or_source.index( '\\' ).nil?
|
22
|
+
shortcut = shortcut_or_source
|
23
|
+
sources = opts.map_fetch_shortcut( shortcut )
|
24
|
+
|
25
|
+
if sources.empty?
|
26
|
+
puts "** Error: No mapping found for shortcut '#{shortcut}'."
|
27
|
+
return
|
28
|
+
end
|
29
|
+
puts " Mapping fetch shortcut '#{shortcut}' to: #{sources.join(',')}"
|
30
|
+
else
|
31
|
+
sources = [shortcut_or_source] # pass arg through unmapped
|
32
|
+
end
|
33
|
+
|
34
|
+
sources.each do |source|
|
35
|
+
install_template( source )
|
36
|
+
end
|
37
|
+
|
38
|
+
end # method run
|
39
|
+
|
40
|
+
|
41
|
+
def install_template( src )
|
42
|
+
# src = 'http://github.com/geraldb/slideshow/raw/d98e5b02b87ee66485431b1bee8fb6378297bfe4/code/templates/fullerscreen.txt'
|
43
|
+
# src = 'http://github.com/geraldb/sandbox/raw/13d4fec0908fbfcc456b74dfe2f88621614b5244/s5blank/s5blank.txt'
|
44
|
+
uri = URI.parse( src )
|
45
|
+
logger.debug "scheme: #{uri.scheme}, host: #{uri.host}, port: #{uri.port}, path: #{uri.path}"
|
46
|
+
|
47
|
+
pakname = File.basename( uri.path ).downcase.gsub('.txt','')
|
48
|
+
pakpath = File.expand_path( "#{opts.config_path}/#{pakname}" )
|
49
|
+
|
50
|
+
logger.debug "packname >#{pakname}<"
|
51
|
+
logger.debug "pakpath >#{pakpath}<"
|
52
|
+
|
53
|
+
Pakman::Fetcher.new.fetch_pak( src, pakpath )
|
54
|
+
end
|
55
|
+
|
56
|
+
end # class Installer
|
57
|
+
|
58
|
+
end # module Pluto
|
data/lib/pluto/lister.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
class Lister
|
4
|
+
|
5
|
+
include LogUtils::Logging
|
6
|
+
|
7
|
+
include ManifestHelper
|
8
|
+
|
9
|
+
def initialize( opts )
|
10
|
+
@opts = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :opts
|
14
|
+
|
15
|
+
def list
|
16
|
+
home = Env.home
|
17
|
+
## replace home w/ ~ (to make out more readable (shorter))
|
18
|
+
## e.g. use gsub( home, '~' )
|
19
|
+
|
20
|
+
puts ''
|
21
|
+
puts 'Installed template packs in search path'
|
22
|
+
|
23
|
+
installed_template_manifest_patterns.each_with_index do |pattern,i|
|
24
|
+
puts " [#{i+1}] #{pattern.gsub(home,'~')}"
|
25
|
+
end
|
26
|
+
puts ' include:'
|
27
|
+
|
28
|
+
manifests = installed_template_manifests
|
29
|
+
if manifests.empty?
|
30
|
+
puts " -- none --"
|
31
|
+
else
|
32
|
+
manifests.each do |manifest|
|
33
|
+
pakname = manifest[0].gsub('.txt','')
|
34
|
+
manifestpath = manifest[1].gsub(home,'~')
|
35
|
+
puts "%16s (%s)" % [pakname,manifestpath]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end # method list
|
39
|
+
|
40
|
+
end # class Lister
|
41
|
+
|
42
|
+
end # module Pluto
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
module ManifestHelper
|
4
|
+
|
5
|
+
## shared methods for handling manifest lookups
|
6
|
+
##
|
7
|
+
# note: required attribs (in host class) include:
|
8
|
+
# - opts.config_path
|
9
|
+
|
10
|
+
def installed_template_manifest_patterns
|
11
|
+
|
12
|
+
# 1) search . # that is, working/current dir
|
13
|
+
# 2) search <config_dir>
|
14
|
+
# 3) search <gem>/templates
|
15
|
+
|
16
|
+
###
|
17
|
+
# Note
|
18
|
+
# -- for now - no longer ship w/ builtin template packs
|
19
|
+
# - download on demand if needed
|
20
|
+
|
21
|
+
builtin_patterns = [
|
22
|
+
## "#{Pluto.root}/templates/*.txt"
|
23
|
+
]
|
24
|
+
config_patterns = [
|
25
|
+
## "#{File.expand_path(opts.config_path)}/*.txt",
|
26
|
+
"#{File.expand_path(opts.config_path)}/*/*.txt"
|
27
|
+
]
|
28
|
+
current_patterns = [
|
29
|
+
## "*.txt",
|
30
|
+
"*/*.txt",
|
31
|
+
"node_modules/*/*.txt", # note: add support for npm installs - use/make slideshow required in name? for namespace in the future???
|
32
|
+
]
|
33
|
+
|
34
|
+
patterns = []
|
35
|
+
patterns += current_patterns
|
36
|
+
patterns += config_patterns
|
37
|
+
patterns += builtin_patterns
|
38
|
+
end
|
39
|
+
|
40
|
+
def installed_template_manifests
|
41
|
+
excludes = [
|
42
|
+
"Manifest.txt",
|
43
|
+
"*/Manifest.txt"
|
44
|
+
]
|
45
|
+
|
46
|
+
Pakman::Finder.new.find_manifests( installed_template_manifest_patterns, excludes )
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end # module Manifest
|
51
|
+
end # module Slideshow
|
data/lib/pluto/models.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# core and stdlibs
|
4
|
+
|
5
|
+
require 'yaml'
|
6
|
+
require 'json'
|
7
|
+
require 'uri'
|
8
|
+
require 'pp'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'logger'
|
11
|
+
require 'date'
|
12
|
+
require 'digest/md5'
|
13
|
+
|
14
|
+
|
15
|
+
# 3rd party ruby gems/libs
|
16
|
+
|
17
|
+
require 'active_record' ## todo: add sqlite3? etc.
|
18
|
+
|
19
|
+
require 'logutils'
|
20
|
+
require 'props' # manage settings/env
|
21
|
+
require 'fetcher' # fetch (download) files
|
22
|
+
require 'pakman' # template pack manager
|
23
|
+
require 'feedutils'
|
24
|
+
require 'textutils'
|
25
|
+
|
26
|
+
require 'activityutils'
|
27
|
+
|
28
|
+
require 'props/activerecord'
|
29
|
+
require 'logutils/activerecord'
|
30
|
+
|
31
|
+
|
32
|
+
# our own code
|
33
|
+
|
34
|
+
require 'pluto/version' # note: let version always get first
|
35
|
+
require 'pluto/schema'
|
36
|
+
require 'pluto/activerecord'
|
37
|
+
|
38
|
+
require 'pluto/models/activity'
|
39
|
+
require 'pluto/models/feed'
|
40
|
+
require 'pluto/models/item'
|
41
|
+
require 'pluto/models/site'
|
42
|
+
require 'pluto/models/subscription'
|
43
|
+
require 'pluto/models/utils'
|
44
|
+
|
45
|
+
require 'pluto/manifest_helpers'
|
46
|
+
require 'pluto/connecter'
|
47
|
+
|
48
|
+
require 'pluto/installer'
|
49
|
+
require 'pluto/fetcher'
|
50
|
+
require 'pluto/refresher'
|
51
|
+
require 'pluto/subscriber'
|
52
|
+
require 'pluto/updater'
|
53
|
+
require 'pluto/lister'
|
54
|
+
require 'pluto/formatter'
|
55
|
+
|
56
|
+
|
57
|
+
module Pluto
|
58
|
+
|
59
|
+
def self.connect!( config=nil ) # convenience shortcut
|
60
|
+
Connecter.new.connect!( config )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# todo: add alias update_site( config ) ??
|
65
|
+
def self.update_subscriptions( config )
|
66
|
+
Subscriber.new.update_subscriptions( config )
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.update_feeds
|
70
|
+
Refresher.new.update_feeds
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.update_sites
|
74
|
+
Refresher.new.update_sites
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.load_tasks
|
78
|
+
# load all builtin Rake tasks (from tasks/*rake)
|
79
|
+
load 'pluto/tasks/env.rake'
|
80
|
+
load 'pluto/tasks/setup.rake'
|
81
|
+
load 'pluto/tasks/stats.rake'
|
82
|
+
load 'pluto/tasks/update.rake'
|
83
|
+
end
|
84
|
+
|
85
|
+
end # module Pluto
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
######
|
90
|
+
# todo - move to ext/array.rb or similar
|
91
|
+
|
92
|
+
class Array
|
93
|
+
|
94
|
+
## todo: check if there's already a builtin method for this
|
95
|
+
#
|
96
|
+
# note:
|
97
|
+
# in rails ary.in_groups(3) results in
|
98
|
+
# top-to-bottom, left-to-right.
|
99
|
+
# and not left-to-right first and than top-to-bottom.
|
100
|
+
#
|
101
|
+
# rename to in_groups_vertical(3) ???
|
102
|
+
|
103
|
+
def in_columns( cols ) # alias for convenience for chunks - needed? why? why not?
|
104
|
+
chunks( cols )
|
105
|
+
end
|
106
|
+
|
107
|
+
def chunks( number_of_chunks )
|
108
|
+
## NB: use chunks - columns might be in use by ActiveRecord!
|
109
|
+
###
|
110
|
+
# e.g.
|
111
|
+
# [1,2,3,4,5,6,7,8,9,10].columns(3)
|
112
|
+
# becomes:
|
113
|
+
# [[1,4,7,10],
|
114
|
+
# [2,5,8],
|
115
|
+
# [3,6,9]]
|
116
|
+
|
117
|
+
## check/todo: make a copy of the array first??
|
118
|
+
# for now reference to original items get added to columns
|
119
|
+
chunks = (1..number_of_chunks).collect { [] }
|
120
|
+
each_with_index do |item,index|
|
121
|
+
chunks[ index % number_of_chunks ] << item
|
122
|
+
end
|
123
|
+
chunks
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# say hello
|
130
|
+
puts Pluto.banner if $DEBUG || (defined?($RUBYLIBS_DEBUG) && $RUBYLIBS_DEBUG)
|
@@ -0,0 +1,127 @@
|
|
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, touched or built use hardcoded 1971-01-01 for now
|
19
|
+
## order( "coalesce(published,touched,built,'1971-01-01') desc" )
|
20
|
+
order( "coalesce(feeds.last_published,'1971-01-01') desc" )
|
21
|
+
end
|
22
|
+
|
23
|
+
##################################
|
24
|
+
# attribute reader aliases
|
25
|
+
#
|
26
|
+
# todo: check if we can use alias_method :name, :title - works for non-existing/on-demand-generated method too??
|
27
|
+
|
28
|
+
def name() title; end # alias for title
|
29
|
+
def description() summary; end # alias for summary -- also add descr shortcut??
|
30
|
+
def link() url; end # alias for url
|
31
|
+
def feed() feed_url; end # alias for feed_url
|
32
|
+
|
33
|
+
def url?() read_attribute(:url).present?; end
|
34
|
+
def title?() read_attribute(:title).present?; end
|
35
|
+
def title2?() read_attribute(:title2).present?; end
|
36
|
+
def feed_url?() read_attribute(:feed_url).present?; end
|
37
|
+
|
38
|
+
def url() read_attribute_w_fallbacks( :url, :auto_url ); end
|
39
|
+
def title() read_attribute_w_fallbacks( :title, :auto_title ); end
|
40
|
+
def title2() read_attribute_w_fallbacks( :title2, :auto_title2 ); end
|
41
|
+
def feed_url() read_attribute_w_fallbacks( :feed_url, :auto_feed_url ); end
|
42
|
+
|
43
|
+
|
44
|
+
def published?() read_attribute(:published).present?; end
|
45
|
+
def touched?() read_attribute(:touched).present?; end
|
46
|
+
|
47
|
+
|
48
|
+
def published
|
49
|
+
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
50
|
+
# db backed attribute
|
51
|
+
|
52
|
+
read_attribute_w_fallbacks(
|
53
|
+
:published,
|
54
|
+
:touched, # try touched (aka updated (ATOM))
|
55
|
+
:built # try build (aka lastBuildDate (RSS))
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def debug=(value) @debug = value; end
|
61
|
+
def debug?() @debug || false; end
|
62
|
+
|
63
|
+
def save_from_struct!( data )
|
64
|
+
|
65
|
+
update_from_struct!( data )
|
66
|
+
|
67
|
+
data.items.each do |item|
|
68
|
+
|
69
|
+
item_rec = Item.find_by_guid( item.guid )
|
70
|
+
if item_rec.nil?
|
71
|
+
item_rec = Item.new
|
72
|
+
puts "** NEW | #{item.title}"
|
73
|
+
else
|
74
|
+
## todo: check if any attribs changed
|
75
|
+
puts "UPDATE | #{item.title}"
|
76
|
+
end
|
77
|
+
|
78
|
+
item_rec.debug = debug? ? true : false # pass along debug flag
|
79
|
+
item_rec.update_from_struct!( self, item )
|
80
|
+
|
81
|
+
end # each item
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def update_from_struct!( data )
|
86
|
+
|
87
|
+
## todo: move to FeedUtils::Feed ??? why? why not??
|
88
|
+
if data.generator
|
89
|
+
generator_full = ''
|
90
|
+
generator_full << data.generator
|
91
|
+
generator_full << " @version=#{data.generator_version}" if data.generator_version
|
92
|
+
generator_full << " @uri=#{data.generator_uri}" if data.generator_uri
|
93
|
+
else
|
94
|
+
generator_full = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
feed_attribs = {
|
98
|
+
format: data.format,
|
99
|
+
published: data.published,
|
100
|
+
touched: data.updated,
|
101
|
+
built: data.built,
|
102
|
+
summary: data.summary,
|
103
|
+
### todo/fix: add/use
|
104
|
+
# auto_title: ???,
|
105
|
+
# auto_url: ???,
|
106
|
+
# auto_feed_url: ???,
|
107
|
+
auto_title2: data.title2,
|
108
|
+
generator: generator_full
|
109
|
+
}
|
110
|
+
|
111
|
+
if debug?
|
112
|
+
## puts "*** dump feed_attribs:"
|
113
|
+
## pp feed_attribs
|
114
|
+
puts "*** dump feed_attribs w/ class types:"
|
115
|
+
feed_attribs.each do |key,value|
|
116
|
+
puts " #{key}: >#{value}< : #{value.class.name}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
update_attributes!( feed_attribs )
|
121
|
+
end
|
122
|
+
|
123
|
+
end # class Feed
|
124
|
+
|
125
|
+
|
126
|
+
end # module Models
|
127
|
+
end # module Pluto
|