pluto 0.7.0 → 0.8.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.
@@ -2,12 +2,27 @@ module Pluto
2
2
 
3
3
  class Opts
4
4
 
5
+ def initialize
6
+ load_shortcuts
7
+ end
8
+
9
+
10
+ def merge_gli_options!( options={} )
11
+ @verbose = true if options[:verbose] == true
12
+
13
+ @config_path = options[:config] if options[:config].present?
14
+ @output_path = options[:output] if options[:output].present?
15
+
16
+ @manifest = options[:template] if options[:template].present?
17
+ end
18
+
19
+
5
20
  def manifest=(value)
6
21
  @manifest = value
7
22
  end
8
23
 
9
24
  def manifest
10
- @manifest || 'blank.txt' ## todo - just return blank (no .txt extension - possible?)
25
+ @manifest || 'blank'
11
26
  end
12
27
 
13
28
  def verbose=(value)
@@ -23,7 +38,8 @@ class Opts
23
38
  end
24
39
 
25
40
  def config_path
26
- @config_path || '~/.pluto'
41
+ ## @config_path || '~/.pluto' --- old code
42
+ @config_path || File.join( Env.home, '.pluto' )
27
43
  end
28
44
 
29
45
 
@@ -35,6 +51,26 @@ class Opts
35
51
  @output_path || '.'
36
52
  end
37
53
 
54
+ def load_shortcuts
55
+ @shortcuts = YAML.load_file( "#{Pluto.root}/config/pluto.index.yml" )
56
+ end
57
+
58
+ def map_fetch_shortcut( key )
59
+ # NB: always returns an array!!! 0,1 or more entries
60
+ # - no value - return empty ary
61
+
62
+ ## todo: normalize key???
63
+ value = @shortcuts.fetch( key, nil )
64
+
65
+ if value.nil?
66
+ []
67
+ elsif value.kind_of?( String )
68
+ [value]
69
+ else # assume it's an array already; ## todo: check if it's an array
70
+ value
71
+ end
72
+ end
73
+
38
74
 
39
75
  end # class Opts
40
76
 
@@ -5,7 +5,7 @@ class Formatter
5
5
  include LogUtils::Logging
6
6
 
7
7
  include Models
8
-
8
+ include ManifestHelper
9
9
 
10
10
  def initialize( opts, config )
11
11
  @opts = opts
@@ -28,10 +28,23 @@ class Formatter
28
28
  manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
29
29
 
30
30
  if manifests.empty?
31
- puts "*** error: unknown template pack '#{manifest_name}'; use pluto -l to list installed template packs"
32
- exit 2
31
+
32
+ ### try - autodownload
33
+ puts "*** template pack '#{manifest_name}' not found; trying auto-install..."
34
+
35
+ Installer.new( opts ).install( manifest_name )
36
+
37
+ ### try again
38
+
39
+ # check for matching manifests
40
+ manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
41
+
42
+ if manifests.empty?
43
+ puts "*** error: unknown template pack '#{manifest_name}'; use pluto ls to list installed template packs"
44
+ exit 2
45
+ end
33
46
  end
34
-
47
+
35
48
  manifestsrc = manifests[0][1]
36
49
  pakpath = opts.output_path
37
50
 
@@ -40,41 +53,6 @@ class Formatter
40
53
  Pakman::Templater.new.merge_pak( manifestsrc, pakpath, binding, name )
41
54
  end
42
55
 
43
- private
44
-
45
- def installed_template_manifest_patterns
46
-
47
- # 1) search . # that is, working/current dir
48
- # 2) search <config_dir>
49
- # 3) search <gem>/templates
50
-
51
- builtin_patterns = [
52
- "#{Pluto.root}/templates/*.txt"
53
- ]
54
- config_patterns = [
55
- "#{File.expand_path(opts.config_path)}/*.txt",
56
- "#{File.expand_path(opts.config_path)}/*/*.txt"
57
- ]
58
- current_patterns = [
59
- "*.txt",
60
- "*/*.txt"
61
- ]
62
-
63
- patterns = []
64
- patterns += current_patterns
65
- patterns += config_patterns
66
- patterns += builtin_patterns
67
- end
68
-
69
- def installed_template_manifests
70
- excludes = [
71
- "Manifest.txt",
72
- "*/Manifest.txt"
73
- ]
74
-
75
- Pakman::Finder.new.find_manifests( installed_template_manifest_patterns, excludes )
76
- end
77
-
78
56
  end # class Formatter
79
57
 
80
58
  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,50 @@
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
+ ]
32
+
33
+ patterns = []
34
+ patterns += current_patterns
35
+ patterns += config_patterns
36
+ patterns += builtin_patterns
37
+ end
38
+
39
+ def installed_template_manifests
40
+ excludes = [
41
+ "Manifest.txt",
42
+ "*/Manifest.txt"
43
+ ]
44
+
45
+ Pakman::Finder.new.find_manifests( installed_template_manifest_patterns, excludes )
46
+ end
47
+
48
+
49
+ end # module Manifest
50
+ end # module Slideshow
data/lib/pluto/models.rb CHANGED
@@ -1,13 +1,42 @@
1
1
  module Pluto
2
2
  module Models
3
-
3
+
4
4
  class Feed < ActiveRecord::Base
5
5
  self.table_name = 'feeds'
6
-
6
+
7
7
  has_many :items
8
8
  has_many :subscriptions
9
9
  has_many :sites, :through => :subscriptions
10
- end
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
+ end
19
+
20
+
21
+ def published_at?
22
+ read_attribute(:published_at).present?
23
+ end
24
+
25
+ def published_at
26
+ ## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
27
+ # db backed attribute
28
+
29
+ if read_attribute(:published_at).present?
30
+ read_attribute(:published_at)
31
+ elsif read_attribute(:touched_at).present?
32
+ ## try touched_at (aka updated (ATOM))
33
+ read_attribute(:touched_at)
34
+ else ## try build_at (aka lastBuildDate (RSS))
35
+ read_attribute(:built_at)
36
+ end
37
+ end
38
+
39
+ end # class Feed
11
40
 
12
41
  class Item < ActiveRecord::Base
13
42
  self.table_name = 'items'
@@ -15,9 +44,30 @@ class Item < ActiveRecord::Base
15
44
  belongs_to :feed
16
45
 
17
46
  def self.latest
18
- order( 'published_at desc' )
47
+ # note: order by first non-null datetime field
48
+ # coalesce - supported by sqlite (yes), postgres (yes)
49
+
50
+ # note: if not published_at,touched_at or built_at use hardcoded 1999-01-01 for now
51
+ order( "coalesce(published_at,touched_at,'1999-01-01') desc" )
19
52
  end
20
- end
53
+
54
+ def published_at?
55
+ read_attribute(:published_at).present?
56
+ end
57
+
58
+ def published_at
59
+ ## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
60
+ # db backed attribute
61
+
62
+ if read_attribute(:published_at).present?
63
+ read_attribute(:published_at)
64
+ else ## try touched_at (aka updated)
65
+ read_attribute(:touched_at)
66
+ end
67
+ end
68
+
69
+ end # class Item
70
+
21
71
 
22
72
  class Site < ActiveRecord::Base
23
73
  self.table_name = 'sites'
@@ -33,6 +83,11 @@ class Subscription < ActiveRecord::Base
33
83
  belongs_to :feed
34
84
  end
35
85
 
86
+ class Action < ActiveRecord::Base
87
+ self.table_name = 'actions'
88
+
89
+ end
90
+
36
91
 
37
92
  end # module Models
38
93
  end # module Pluto
data/lib/pluto/schema.rb CHANGED
@@ -5,9 +5,11 @@ class CreateDb < ActiveRecord::Migration
5
5
 
6
6
  def up
7
7
  create_table :sites do |t|
8
- t.string :title, :null => false # e.g Planet Ruby, Planet JavaScript, etc.
9
- t.string :key, :null => false # e.g. ruby, js, etc.
10
- t.timestamps
8
+ t.string :title, :null => false # e.g Planet Ruby, Planet JavaScript, etc.
9
+ t.string :key, :null => false # e.g. ruby, js, etc.
10
+ t.datetime :fetched_at # last fetched/checked date -- make not null ??
11
+
12
+ t.timestamps # created_at, updated_at
11
13
  end
12
14
 
13
15
  create_table :subscriptions do |t| # has_many join table (sites/feeds)
@@ -18,21 +20,51 @@ class CreateDb < ActiveRecord::Migration
18
20
 
19
21
  create_table :feeds do |t|
20
22
  t.string :title, :null => false
23
+ t.string :title2 # e.g. subtitle (atom)
24
+ t.text :summary # e.g. description (rss)
21
25
  t.string :url, :null => false
22
26
  t.string :feed_url, :null => false
27
+ t.string :generator # feed generator (e.g. wordpress, etc.) from feed
28
+
29
+ t.datetime :published_at # from feed published(atom)+ pubDate(rss)
30
+ t.datetime :built_at # from feed lastBuiltDate(rss)
31
+ t.datetime :touched_at # from feed updated(atom)
32
+
33
+ # -- our own (meta) fields
23
34
  t.string :key, :null => false
24
- t.timestamps
35
+ t.string :format # e.g. atom (1.0), rss 2.0, rss 0.7 etc.
36
+ t.string :etag # last etag
37
+ t.datetime :fetched_at # last fetched/checked date
38
+ t.timestamps # created_at, updated_at
25
39
  end
26
40
 
27
41
  create_table :items do |t|
28
42
  t.string :title # todo: add some :null => false ??
29
- t.string :url
30
43
  t.string :guid
44
+ t.string :url
45
+ t.text :summary # e.g. description (rss), summary (atom)
31
46
  t.text :content
32
- t.datetime :published_at
47
+
48
+ t.datetime :published_at # from feed (published) + pubDate(rss)
49
+ t.datetime :touched_at # from feed updated (atom)
50
+
51
+ ## todo: add :last_updated_at ?? (NOTE: updated_at already take by auto-timestamps)
33
52
  t.references :feed, :null => false
53
+
54
+ t.datetime :fetched_at # last fetched/check date
55
+ t.timestamps # created_at, updated_at
56
+
57
+ ## t.string :author
58
+ ## todo: add author/authors, category/categories
59
+ end
60
+
61
+ create_table :actions do |t|
62
+ t.string :title # e.g. new site, new subscription, update feeds, etc.
63
+ t.string :object # todo: find better names for action attribs ??
64
+ t.string :object_type
34
65
  t.timestamps
35
66
  end
67
+
36
68
  end
37
69
 
38
70
  def down