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