pluto 0.7.0 → 0.8.0

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