pluto-models 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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,8 @@
1
+ module Pluto
2
+ module Models
3
+
4
+ # add shortcut/alias
5
+ Activity = ActivityDb::Models::Activity
6
+
7
+ end # module Models
8
+ end # module Pluto
@@ -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