podgraph 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS CHANGED
@@ -1,12 +1,34 @@
1
1
  -*- text -*-
2
2
 
3
+ 0.0.5
4
+ -----
5
+
6
+ Wed Apr 20 21:58:27 EEST 2011
7
+
8
+ - If no input file is specified, read stdin.
9
+
10
+ - Repackaged under RVM in fedora.
11
+
12
+ 0.0.4
13
+ -----
14
+
15
+ Tue Apr 19 19:01:14 EEST 2011
16
+
17
+ - Fixed one RE to support https:// images.
18
+
19
+ - Dropped activesupport dependency.
20
+
21
+ - Injected falsework's naive template.
22
+
3
23
  0.0.3
24
+ -----
4
25
 
5
- - add missing active_support dependency (btw, active_support 3.0.0
6
- requires i18n (ran `gem install i18n) but it's not listed in its
7
- dependencies)
26
+ - added missing activesupport dependency (btw, activesupport 3.0.0
27
+ requires i18n (run 'gem install i18n', for some reason this dependency
28
+ isn't listed in the gem).
8
29
 
9
30
  0.0.2
31
+ -----
10
32
 
11
33
  - nailed the mail gem to explicit version 2.1.3, because the current
12
34
  2.2.0 introduced some weird bugs.
data/README.rdoc CHANGED
@@ -1,41 +1,41 @@
1
- -*- text -*-
2
1
  = Name
3
2
 
4
- podgraph -- Create an email from a XHTML and inline images and send it
5
- to posterous.com.
3
+ podgraph -- Create an email from XHTML + inline images and send it to
4
+ posterous.com.
6
5
 
7
6
  = Synopsis
8
7
 
9
- podgraph [-Sv] [-m ARG] file.html
8
+ podgraph [-Sv] [-m ARG] [file.html]
10
9
 
11
10
  = Description
12
11
 
13
- It's a simple program that reads a XHTML file, extracts subject and body
14
- from the file, constructs an email and delivers it.
12
+ It is a simple program that reads a XHTML file (or stdin), extracts
13
+ subject and body from the file, constructs an email and delivers it to
14
+ local MTA.
15
15
 
16
16
  The options are as follows:
17
17
 
18
18
  -v Be more verbose.
19
19
  -S Don't send, just dump the mail to stdout.
20
- -m ARG 1 of modes: Podgraph::["related", "mixed"].
20
+ -m ARG 1 of modes: related, mixed.
21
21
 
22
- The file is supposed to be a XHTML result from python's docutils
22
+ The file is supposed to be a XHTML generated by python's docutils from
23
23
  reStructuredText. The idea is:
24
24
 
25
- 1. You're writing a post (for example, for posterous.com) in
26
- reStructuredText in Emacs.
25
+ 1. Write a post (for example, for posterous.com) in reStructuredText in
26
+ Emacs.
27
27
 
28
- 2. You're converting it with help of docutils to the XHTML.
28
+ 2. Convert it with help of docutils to the XHTML.
29
29
 
30
- 3. Finally, you're creating a proper MIME mail from raw XHTML and
31
- sending it to posterous.com.
30
+ 3. Finally, create a proper MIME mail from the raw XHTML and send it to
31
+ posterous.com.
32
32
 
33
- Step 3 is what podgraph does.
33
+ <em>Step 3 is what podgraph does.</em>
34
34
 
35
35
  == Features
36
36
 
37
- * Creates mails with inline images if it can found links in the XHTML
38
- file to local images.
37
+ * Generates mail with inline images if it can found links to local
38
+ images in the XHTML file.
39
39
 
40
40
  * Charset of 'text/html' portion of a mail is always UTF-8.
41
41
 
@@ -46,7 +46,7 @@ or >= 1 if en error occurs.
46
46
 
47
47
  = Examples
48
48
 
49
- Create a config.yaml file in the directory with your writing. For
49
+ Create a config.yaml file in the directory with your writings. For
50
50
  example:
51
51
 
52
52
  % cd ~/lib/writing/posterous
@@ -64,7 +64,7 @@ To give podgraph a chance to find a subject for the mail, write .rest
64
64
  file as:
65
65
 
66
66
  This is a subject
67
- *****************
67
+ -----------------
68
68
 
69
69
  My usual reStructuredText.
70
70
 
@@ -86,8 +86,8 @@ Also, you can preview the mail without sending it:
86
86
  % podgraph -S 0001.html
87
87
 
88
88
  If you have links to local images in your .rest file (and
89
- correspondingly in .html) then podgraph will include images in the mail as
90
- inline images. But if you don't want this and want images to become a
89
+ correspondingly in .html) then podgraph will include images in the mail
90
+ as inline images. But if you don't want this and want images to become a
91
91
  typical gallery on posterous.com, run:
92
92
 
93
93
  % podgraph -m mixed 0001.html
data/Rakefile CHANGED
@@ -1,39 +1,42 @@
1
- # -*- ruby -*-
2
-
3
1
  require 'rake'
4
2
  require 'rake/gempackagetask'
5
3
  require 'rake/clean'
6
4
  require 'rake/rdoctask'
7
5
  require 'rake/testtask'
8
6
 
7
+ require_relative 'lib/podgraph/meta'
8
+ require_relative 'test/rake_git'
9
+
9
10
  spec = Gem::Specification.new do |s|
10
- s.name = "podgraph"
11
+ s.name = Podgraph::Meta::NAME
12
+ s.version = Podgraph::Meta::VERSION
11
13
  s.summary = 'Creates a MIME mail from a XHTML source and delivers it to Posterous.com.'
12
- s.version = '0.0.3'
13
- s.author = 'Alexander Gromnitsky'
14
- s.email = 'alexander.gromnitsky@gmail.com'
14
+ s.description = 'Adequately scans XHTML for local inline images and appends them to the mail.'
15
+ s.author = Podgraph::Meta::AUTHOR
16
+ s.email = Podgraph::Meta::EMAIL
17
+ s.homepage = Podgraph::Meta::HOMEPAGE
15
18
  s.platform = Gem::Platform::RUBY
16
- s.required_ruby_version = '>= 1.9'
17
- s.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
18
- s.executables = ['podgraph']
19
- s.has_rdoc = true
20
- s.test_files = FileList['test/ts_*.rb'].to_a
19
+ s.required_ruby_version = '>= 1.9.2'
20
+ s.files = git_ls('.')
21
+ s.executables = [s.name]
22
+
23
+ s.test_files = FileList['test/test_*.rb']
21
24
  s.rdoc_options << '-m' << 'Podgraph'
25
+
26
+ s.add_dependency('mail', '~> 2.2.17')
27
+ s.add_development_dependency('git', '>= 1.2.5')
22
28
  end
23
- spec.add_dependency('mail', '= 2.1.3')
24
- spec.add_dependency('activesupport', '>= 3.0.0')
25
29
 
26
30
  Rake::GemPackageTask.new(spec).define
27
31
 
28
- task :default => %(repackage)
32
+ task default: [:repackage]
29
33
 
30
34
  Rake::RDocTask.new('doc') do |rd|
31
35
  rd.main = "Podgraph"
32
- rd.rdoc_dir = 'doc'
33
36
  rd.rdoc_files.include("lib/**/*.rb")
34
37
  end
35
38
 
36
39
  Rake::TestTask.new do |t|
37
- t.test_files = FileList['test/ts_*.rb']
40
+ t.test_files = FileList['test/test_*.rb']
38
41
  t.verbose = true
39
42
  end
data/TODO CHANGED
@@ -1,11 +1,9 @@
1
- -*- text -*-
1
+ -*-org-*-
2
2
 
3
- 0.1.2
4
-
5
- - read input from stdin
3
+ * 0.1.0
6
4
  - CL options for email
7
5
 
8
- 0.0.1
6
+ * 0.0.1
9
7
 
10
8
  + rewrite README.rdoc to make it look more like a manpage
11
9
  + add simple tests
data/bin/podgraph CHANGED
@@ -1,76 +1,57 @@
1
1
  #!/usr/bin/env ruby19
2
2
  # -*- ruby -*-
3
3
 
4
- # Copyright (c) 2010 Alexander Gromnitsky <mailto:alexander.gromnitsky@gmail.com>.
5
- #
6
- # $Id: podgraph 128 2010-04-24 07:16:01Z alex $
7
-
8
4
  require_relative '../lib/podgraph/posterous'
9
5
 
10
- $conf = {
11
- prog_ver: '0.0.3',
12
- send?: true,
13
- config: 'config.yaml',
14
- modes: %w(related mixed),
15
- mode: 'related',
16
- to: nil,
17
- from: nil
18
- }
6
+ $conf = {}
7
+ u = Trestle.new $conf
8
+
9
+ $conf[:send?] = true
10
+ $conf[:mailconfig] = 'config.yaml'
11
+ $conf[:modes] = %w(related mixed)
12
+ $conf[:mode] = 'related'
13
+ $conf[:to] = nil
14
+ $conf[:from] = nil
15
+ $conf[:banner] = "#{File.basename($0)} [options] [file.html]\nType 'ri #{Podgraph::Meta::NAME.capitalize}' for the help."
16
+ $conf[:input] = nil
19
17
 
20
- def config_load()
18
+ def mailconfig_load()
21
19
  begin
22
- myconf = YAML.load_file($conf[:config])
20
+ myconf = YAML.load_file($conf[:mailconfig])
23
21
  rescue
24
- abort("cannot parse #{$conf[:config]} in the current directory")
22
+ abort("cannot parse #{$conf[:mailconfig]} in the current directory")
25
23
  end
26
24
  %w(to from).each { |i|
27
- abort("missing #{i} in #{$conf[:config]}") if ! myconf.key?(i.to_sym)
25
+ Trestle.errx(1, "missing #{i} in #{$conf[:mailconfig]}") if ! myconf.key?(i.to_sym)
28
26
  }
29
27
  $conf.merge!(myconf)
30
28
  end
31
29
 
32
- def cl_parse(myargs)
33
- o = OptionParser.new()
34
- o.banner = "#{File.basename($PROGRAM_NAME)} #{$conf[:prog_ver]}.
35
- Create an email from a XHTML and inline images and send it to posterous.com.
36
- http://podgraph.posterous.com/
37
30
 
38
- Usage: #{File.basename($PROGRAM_NAME)} [options] file.html"
39
- o.separator ""
40
- o.on('-v', 'Be more verbose.') { |v| Podgraph::cfg[:verbose] += 1 }
41
- o.on('-S', "Don't send, just dump the mail to stdout.") { |v| $conf[:send?] = false }
42
- o.on('-m ARG', "1 of modes: Podgraph::#{$conf[:modes]}.",
43
- $conf[:modes]) { |v| $conf[:mode] = v }
31
+ # ---
44
32
 
45
- begin
46
- o.parse!(myargs)
47
- rescue
48
- abort("cl parse error: #{$!}")
49
- end
50
- end
51
-
52
- # --[ main ]------------------------------------------------------------
53
-
54
- config_load()
33
+ u.config_parse(['foobar']) {|src|
34
+ o = u.cl_parse(src) # create an OptionParser object
35
+ o.on('-c ARG', "Use another configuration file instead of",
36
+ $conf[:mailconfig]) { |v| $conf[:mailconfig] = v }
37
+ o.on('-S', "Don't send, just dump the mail to stdout") { |v| $conf[:send?] = false }
38
+ o.on('-m ARG', "Select mode: #{$conf[:modes].join(', ')}") { |v| $conf[:mode] = v }
39
+ u.cl_parse(src, o) # run cl parser
40
+ }
55
41
 
56
- cl_parse ARGV
57
- Podgraph::veputs(1, "CL options: #{ARGV}")
58
- unless ARGV.size >= 1
59
- abort("Usage: #{File.basename($PROGRAM_NAME)} [options] filename.html
60
- Type \"#{File.basename($PROGRAM_NAME)} -h\" for the help.")
61
- end
42
+ ARGV.size < 1 ? $conf[:input] = STDIN : $conf[:input] = ARGV[0]
43
+ mailconfig_load
62
44
 
63
- Podgraph::veputs(2, "cfg #{Podgraph::cfg}")
64
45
  begin
65
- p = Podgraph::Posterous.new(ARGV[0], $conf[:to], $conf[:from], $conf[:mode])
66
- Podgraph::veputs(2, "o: #{p.o}".to_s.encode('koi8-u'))
67
- mail = p.generate()
46
+ p = Podgraph::Posterous.new(u, $conf[:input], $conf[:to], $conf[:from], $conf[:mode])
47
+ u.veputs(2, "o: #{p.o}".to_s.encode('koi8-u'))
48
+ mail = p.generate
68
49
  rescue
69
- abort("HTML parsing failed: #{$!}")
50
+ Trestle.errx(1, "HTML parsing failed: #{$!}")
70
51
  end
71
52
 
72
53
  if ! $conf[:send?]
73
- puts mail.to_s()
54
+ puts mail.to_s
74
55
  exit 0
75
56
  end
76
57
 
@@ -78,5 +59,5 @@ begin
78
59
  mail.delivery_method :sendmail
79
60
  mail.deliver
80
61
  rescue
81
- abort("cannot send mail: #{$!}")
62
+ Trestle.errx(1, "cannot send mail: #{$!}")
82
63
  end
@@ -0,0 +1,9 @@
1
+ module Podgraph
2
+ module Meta
3
+ NAME = 'podgraph'
4
+ VERSION = '0.0.5'
5
+ AUTHOR = 'Alexander Gromnitsky'
6
+ EMAIL = 'alexander.gromnitsky@gmail.com'
7
+ HOMEPAGE = 'http://github.com/gromnitsky/' + NAME
8
+ end
9
+ end
@@ -1,26 +1,13 @@
1
- # $Id: posterous.rb 128 2010-04-24 07:16:01Z alex $
2
-
3
- gem 'mail', '= 2.1.3'
4
1
  require 'mail'
5
- require 'active_support/core_ext/module/attribute_accessors'
6
-
7
2
  require 'rexml/document'
8
3
  require 'yaml'
9
4
  require 'optparse'
10
5
 
6
+ require_relative 'trestle'
7
+ include Podgraph
8
+
11
9
  # :include: ../../README.rdoc
12
10
  module Podgraph
13
-
14
- VERSION = '0.0.3'
15
- mattr_accessor :cfg
16
-
17
- self.cfg = Hash.new()
18
- cfg[:verbose] = 0
19
-
20
- def self.veputs(level, s)
21
- puts(s) if cfg[:verbose] >= level
22
- end
23
-
24
11
  # Reads XHTML file, analyses it, finds images, checks if they can be inlined,
25
12
  # generates multipart/relative or multipart/mixed MIME mail.
26
13
  class Posterous
@@ -28,12 +15,15 @@ module Podgraph
28
15
  # some options for mail generator; change with care
29
16
  attr_accessor :o
30
17
 
18
+ # a Trestle object
19
+ attr_accessor :trestle
20
+
31
21
  # Analyses _filename_. It must be a XHTML file.
32
22
  # _to_, _from_ are email.
33
23
  # _mode_ is 1 of 'related' or 'mixed' string.
34
- def initialize(filename, to, from, mode)
24
+ def initialize(trestle, filename, to, from, mode)
35
25
  @o = Hash.new()
36
- @o[:user_agent] = 'podgraph/' + VERSION
26
+ @o[:user_agent] = Podgraph::Meta::NAME + ?/ + Podgraph::Meta::VERSION
37
27
  @o[:subject] = ''
38
28
  @o[:body] = []
39
29
  @o[:attachment] = []
@@ -42,13 +32,15 @@ module Podgraph
42
32
  @o[:to] = to
43
33
  @o[:from] = from
44
34
 
45
- fp = File.new(filename)
35
+ @trestle = trestle
36
+
37
+ fp = (filename == STDIN ? STDIN : File.new(filename))
46
38
  begin
47
39
  make(fp)
48
40
  rescue
49
41
  raise $!
50
42
  ensure
51
- fp.close()
43
+ fp.close unless fp == STDIN
52
44
  end
53
45
  end
54
46
 
@@ -65,7 +57,7 @@ module Podgraph
65
57
  if i.name == 'img'
66
58
  if (src = i.attributes['src']) =~ /^\s*$/
67
59
  raise '<img> tag with missing or empty src attribute'
68
- elsif src =~ /\s*(http|ftp):\/\//
60
+ elsif src =~ /\s*(https?|s?ftp):\/\//
69
61
  # we are ignoring URL's
70
62
  return
71
63
  else
@@ -77,7 +69,7 @@ module Podgraph
77
69
  i.attributes['src'] = random
78
70
  @o[:a_marks][src] = random # save an act of the replacement
79
71
 
80
- @o.rehash() # does is this really necessary?
72
+ @o.rehash() # is this really necessary?
81
73
  end
82
74
  end
83
75
  end
@@ -90,10 +82,10 @@ module Podgraph
90
82
  next
91
83
  end
92
84
 
93
- Podgraph::veputs(2, "node: #{i.name}")
85
+ @trestle.veputs(2, "node: #{i.name}")
94
86
  img_collect.call(i, @o[:attachment])
95
87
  i.each_recursive { |j|
96
- Podgraph::veputs(2, "node recursive: #{j.name}")
88
+ @trestle.veputs(2, "node recursive: #{j.name}")
97
89
  img_collect.call(j, @o[:attachment])
98
90
  }
99
91
 
@@ -109,11 +101,12 @@ module Podgraph
109
101
  m = Mail.new()
110
102
  m.from(@o[:from])
111
103
  m.to(@o[:to])
112
- m.content_transfer_encoding('8bit')
104
+ m.transport_encoding = Mail::Encodings.get_encoding('8bit')
105
+ # m.content_transfer_encoding('8bit')
113
106
  m.subject(@o[:subject])
114
107
  m.headers({'User-Agent' => @o[:user_agent]})
115
108
 
116
- Podgraph::veputs(2, "Body lines=#{@o[:body].size}, bytes=#{@o[:body].to_s.bytesize}")
109
+ @trestle.veputs(2, "Body lines=#{@o[:body].size}, bytes=#{@o[:body].to_s.bytesize}")
117
110
  if @o[:attachment].size == 0
118
111
  m.content_disposition('inline')
119
112
  m.content_type('text/html; charset="UTF-8"')
@@ -123,7 +116,6 @@ module Podgraph
123
116
  m.content_type('Multipart/Related')
124
117
  end
125
118
  m.html_part = Mail::Part.new {
126
- content_transfer_encoding('8bit')
127
119
  content_type('text/html; charset=UTF-8')
128
120
  }
129
121
  m.html_part.body = @o[:body]
@@ -147,7 +139,7 @@ module Podgraph
147
139
 
148
140
  @o[:a_marks].each { |k, v|
149
141
  if cid.key?(k)
150
- Podgraph::veputs(2, "mark #{k} = #{v}; -> to #{cid[k]}")
142
+ @trestle.veputs(2, "mark #{k} = #{v}; -> to #{cid[k]}")
151
143
  # replace marks with corresponding content-id
152
144
  m.html_part.body.raw_source.sub!(v, "cid:#{cid[k][1..-1]}")
153
145
  else
@@ -0,0 +1,216 @@
1
+ # :erb:
2
+ require 'yaml'
3
+ require 'shellwords.rb'
4
+ require 'optparse'
5
+ require 'pp'
6
+ require 'open4'
7
+
8
+ require_relative 'meta'
9
+
10
+ # :include: ../../README.rdoc
11
+ module Podgraph
12
+
13
+ class Trestle
14
+
15
+ # Execute _cmd_ and return a list [exit_status, stderr,
16
+ # stdout]. Very handy.
17
+ def self.cmd_run(cmd)
18
+ so = sr = ''
19
+ status = Open4::popen4(cmd) { |pid, stdin, stdout, stderr|
20
+ so = stdout.read
21
+ sr = stderr.read
22
+ }
23
+ [status.exitstatus, sr, so]
24
+ end
25
+
26
+ # Return a directory with program libraries.
27
+ def self.gem_libdir
28
+ t = ["#{File.dirname(File.expand_path($0))}/../lib/#{Podgraph::Meta::NAME}",
29
+ "#{Gem.dir}/gems/#{Podgraph::Meta::NAME}-#{Podgraph::Meta::VERSION}/lib/#{Podgraph::Meta::NAME}",
30
+ "lib/#{Podgraph::Meta::NAME}"]
31
+ t.each {|i| return i if File.readable?(i) }
32
+ fail "all paths are invalid: #{t}"
33
+ end
34
+
35
+ # Analogue to shell command +which+.
36
+ def self.in_path?(file)
37
+ return true if file =~ %r%\A/% and File.exist? file
38
+
39
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path|
40
+ File.exist? File.join(path, file)
41
+ end
42
+ end
43
+
44
+ # Print an error message _t_ and exit if _ec_ > 0.
45
+ def self.errx(ec, t)
46
+ STDERR.puts File.basename($0) + ' error: ' + t.to_s
47
+ exit ec if ec > 0
48
+ end
49
+
50
+ # Print a warning.
51
+ def self.warnx(t)
52
+ STDERR.puts File.basename($0) + ' warning: ' + t.to_s
53
+ end
54
+
55
+ # #veputs uses this to decide to put a newline or not to put.
56
+ NNL_MARK = '__NNL__'
57
+
58
+ # Use this in your CL options to check if modifying some variable is
59
+ # not an idempotent act.
60
+ attr_reader :cl_opt_protect
61
+
62
+ # [conf] Typically must be a reference to some global variable.
63
+ def initialize(conf)
64
+ @conf = conf
65
+ @conf[:verbose] = 0
66
+ @conf[:banner] = "Usage: #{File.basename($0)} [options]"
67
+ @conf[:config] = Meta::NAME + '.yaml'
68
+ @conf[:config_dirs] = [ENV['HOME']+'/.'+Meta::NAME,
69
+ File.absolute_path("#{File.dirname(File.expand_path($0))}/../etc"),
70
+ '/usr/etc', '/usr/local/etc', '/etc',
71
+ "#{Gem.dir}/gems/#{Meta::NAME}-#{Meta::VERSION}/etc"
72
+ ]
73
+ @conf[:config_env] = [Meta::NAME.upcase + '_CONF']
74
+
75
+ @cl_parsing_times = 0 # not used
76
+ @cl_opt_protect = false
77
+ end
78
+
79
+ # [level] A verbose level.
80
+ # [t] A string to print.
81
+ #
82
+ # Don't print _t_ with a newline if it contains NNL_MARK at the end.
83
+ def veputs(level, t)
84
+ t = t.dup
85
+ nnl = nil
86
+ if t.match(/#{NNL_MARK}$/)
87
+ t.sub!(/#{$&}/, '')
88
+ nnl = 1
89
+ end
90
+
91
+ if @conf[:verbose] >= level
92
+ nnl ? print(t) : puts(t)
93
+ STDOUT.flush
94
+ end
95
+ end
96
+
97
+ # Run all configuration parsing in a batch.
98
+ #
99
+ # [rvars] A list of variable names which must be in the
100
+ # configuration file.
101
+ #
102
+ # If no block is given, only standard CL options will be analysed.
103
+ def config_parse(rvars, &block)
104
+ cb = ->(b, src) {
105
+ if b
106
+ block.call src
107
+ else
108
+ # very basic default options
109
+ cl_parse(src, nil, true)
110
+ end
111
+ }
112
+
113
+ # 1. parse env
114
+ @conf[:config_env].each {|i|
115
+ # puts '0 run:'
116
+ cb.call(block_given?, ENV[i].shellsplit) if ENV.key?(i)
117
+ }
118
+
119
+ # 2. parse CL in case of '--config' option
120
+ # puts "\n1 run"
121
+ @cl_opt_protect = true
122
+ cb.call(block_given?, ARGV.dup)
123
+ @cl_opt_protect = false
124
+
125
+ # 3. load the configuration file & do the final CL parsing
126
+ begin
127
+ # puts "\n2 run"
128
+ r = config_flat_load(rvars)
129
+ rescue
130
+ Trestle.errx(1, "cannot load config: #{$!}")
131
+ end
132
+ veputs(1, "Loaded config: #{r}")
133
+ cb.call(block_given?, ARGV)
134
+ end
135
+
136
+ # Load a config file immediately if it contains '/' in its name,
137
+ # otherwise search through several dirs for it.
138
+ #
139
+ # [rvars] a list of requied variables in the config
140
+ #
141
+ # Return a loaded filename or nil on error.
142
+ def config_flat_load(rvars)
143
+ p = ->(f) {
144
+ if File.readable?(f)
145
+ begin
146
+ myconf = YAML.load_file(f)
147
+ rescue
148
+ abort("cannot parse #{f}: #{$!}")
149
+ end
150
+ rvars.each { |i|
151
+ fail "missing or nil '#{i}' in #{f}" if ! myconf.key?(i.to_sym) || ! myconf[i.to_sym]
152
+ }
153
+ @conf.merge!(myconf)
154
+ return @conf[:config]
155
+ end
156
+ return nil
157
+ }
158
+
159
+ if @conf[:config].index('/')
160
+ return p.call(@config[:config])
161
+ else
162
+ @conf[:config_dirs].each {|dir|
163
+ return dir+'/'+@conf[:config] if p.call(dir + '/' + @conf[:config])
164
+ }
165
+ end
166
+
167
+ return nil
168
+ end
169
+
170
+
171
+ # Parses CL-like options.
172
+ #
173
+ # [src] An array of options (usually +ARGV+).
174
+ #
175
+ # If _o_ is non nil function parses _src_ immediately, otherwise it
176
+ # only creates +OptionParser+ object and return it (if _simple_ is
177
+ # false).
178
+ def cl_parse(src, o = nil, simple = false)
179
+ if ! o then
180
+ # puts "NEW o (#{cl_opt_protect})" + src.to_s
181
+ o = OptionParser.new
182
+ o.banner = @conf[:banner]
183
+ o.on('-v', 'Be more verbose.') { |i|
184
+ # puts "cl_parsing_times "+cl_parsing_times.to_s
185
+ @conf[:verbose] += 1 unless cl_opt_protect
186
+ }
187
+ o.on('-V', 'Show version & exit.') { |i|
188
+ puts Meta::VERSION
189
+ exit 0
190
+ }
191
+ o.on('--config NAME', "Set a config name (default is #{@conf[:config]})") {|i|
192
+ @conf[:config] = i
193
+ }
194
+ o.on('--config-dirs', 'Show possible config locations') {
195
+ @conf[:config_dirs].each { |j|
196
+ f = j + '/' + @conf[:config]
197
+ puts (File.readable?(f) ? '* ' : ' ') + f
198
+ }
199
+ exit 0
200
+ }
201
+
202
+ return o if ! simple
203
+ end
204
+
205
+ begin
206
+ o.parse!(src)
207
+ @cl_parsing_times += 1
208
+ rescue
209
+ Trestle.errx(1, $!.to_s)
210
+ end
211
+ end
212
+
213
+ end # trestle
214
+ end
215
+
216
+ # Don't remove this: falsework/0.2.2/naive/2010-12-26T04:50:00+02:00
data/test/.document ADDED
File without changes
data/test/helper.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'helper_trestle'
2
+
3
+ require 'digest/md5'
@@ -0,0 +1,37 @@
1
+ # :erb:
2
+ # Various staff for minitest. Include this file into your 'helper.rb'.
3
+
4
+ require 'fileutils'
5
+ include FileUtils
6
+
7
+ require_relative '../lib/podgraph/trestle'
8
+ include Podgraph
9
+
10
+ # don't run tests automatically if they were invoked as 'gem check -t ...'
11
+ if $0 =~ /gem/
12
+ require 'minitest/unit'
13
+ else
14
+ require 'minitest/autorun'
15
+ end
16
+
17
+ # Return the right directory for (probably executable) _c_.
18
+ def cmd(c)
19
+ case File.basename(Dir.pwd)
20
+ when Meta::NAME.downcase
21
+ # test probably is executed from the Rakefile
22
+ Dir.chdir('test')
23
+ when 'test'
24
+ # we are in the test directory, there is nothing special to do
25
+ else
26
+ # tests were invoked by 'gem check -t podgraph'
27
+ begin
28
+ Dir.chdir(Trestle.gem_libdir + '/../../test')
29
+ rescue
30
+ raise "running tests from '#{Dir.pwd}' isn't supported: #{$!}"
31
+ end
32
+ end
33
+
34
+ '../bin/' + c
35
+ end
36
+
37
+ # Don't remove this: falsework/0.2.2/naive/2010-12-26T04:50:00+02:00
data/test/rake_git.rb ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ # -*-ruby-*-
3
+ # :erb:
4
+
5
+ # This is a helper for your Rakefile. Read the comments for each
6
+ # function.
7
+
8
+ require 'git'
9
+ require 'pp'
10
+
11
+ # Return a list of files in a git repository _repdir_.
12
+ #
13
+ # Add this to your gem spec:
14
+ #
15
+ # spec = Gem::Specification.new {|i|
16
+ # i.files = git_ls('.')
17
+ # }
18
+ #
19
+ # What it does is just collecting the list of the files from the git
20
+ # repository. The idea is to use that list for the gem spec. No more
21
+ # missing or redundant files in gems!
22
+ def git_ls(repdir, ignore_some = true)
23
+ ignore = ['/?\.gitignore$']
24
+
25
+ r = []
26
+ g = Git.open repdir
27
+ g.ls_files.each {|i, v|
28
+ next if ignore_some && ignore.index {|ign| i.match(/#{ign}/) }
29
+ r << i
30
+ }
31
+ r
32
+ end
33
+
34
+ pp git_ls('.') if __FILE__ == $0
35
+
36
+ # Don't remove this: falsework/0.2.2/naive/2010-12-26T04:50:00+02:00
data/test/simple.html CHANGED
@@ -2,7 +2,8 @@
2
2
  <body>
3
3
  <div>
4
4
  <h1>Really, dude</h1>
5
- <p>Here is nothing <i>interesting</i>.</p>
5
+ <p>Here is nothing <i>
6
+ interesting</i>.</p>
6
7
  </div>
7
8
  </body>
8
9
  </html>
@@ -1,65 +1,65 @@
1
- require 'test/unit'
2
- require 'digest/md5'
3
-
1
+ require_relative 'helper'
4
2
  require_relative '../lib/podgraph/posterous'
5
3
 
6
- class TestMime < Test::Unit::TestCase
4
+ class TestMime < MiniTest::Unit::TestCase
7
5
  def setup
8
6
  @testdir = File.expand_path(File.dirname(__FILE__))
9
7
  @to = 'alex@goliard'
10
8
  @from = 'alexander.gromnitsky@gmail.com'
9
+ @conf = {}
10
+ @u = Trestle.new @conf
11
11
  end
12
12
 
13
13
  def test_broken_subject
14
- e = assert_raise(RuntimeError) {
15
- p = Podgraph::Posterous.new(@testdir+'/nosubject.html', @to,
14
+ e = assert_raises(RuntimeError) {
15
+ p = Podgraph::Posterous.new(@u, @testdir+'/nosubject.html', @to,
16
16
  @from, 'related')
17
17
  }
18
18
  assert_match(/cannot extract the subject/, e.message)
19
19
  end
20
20
 
21
21
  def test_missing_input_file
22
- e = assert_raise(Errno::ENOENT) {
23
- p = Podgraph::Posterous.new('something_completly_unreliable.html',
22
+ e = assert_raises(Errno::ENOENT) {
23
+ p = Podgraph::Posterous.new(@u, 'something_completly_unreliable.html',
24
24
  @to, @from, 'related')
25
25
  }
26
26
  assert_match(/no such file or directory/i, e.message)
27
27
  end
28
28
 
29
29
  def test_empty_input_file
30
- e = assert_raise(RuntimeError) {
31
- p = Podgraph::Posterous.new(@testdir+'/empty.html',
30
+ e = assert_raises(RuntimeError) {
31
+ p = Podgraph::Posterous.new(@u, @testdir+'/empty.html',
32
32
  @to, @from, 'related')
33
33
  }
34
34
  assert_match(/cannot extract the subject/, e.message)
35
35
  end
36
36
 
37
37
  def test_invalid_input_file_01
38
- e = assert_raise(RuntimeError) {
39
- p = Podgraph::Posterous.new(@testdir+'/garbage_01.html',
38
+ e = assert_raises(RuntimeError) {
39
+ p = Podgraph::Posterous.new(@u, @testdir+'/garbage_01.html',
40
40
  @to, @from, 'related')
41
41
  }
42
42
  assert_match(/cannot extract the subject/, e.message)
43
43
  end
44
44
 
45
45
  def test_invalid_input_file_02
46
- assert_raise(REXML::ParseException) {
47
- p = Podgraph::Posterous.new(@testdir+'/garbage_02.html',
46
+ assert_raises(REXML::ParseException) {
47
+ p = Podgraph::Posterous.new(@u, @testdir+'/garbage_02.html',
48
48
  @to, @from, 'related')
49
49
  }
50
50
  end
51
51
 
52
52
  def test_invalid_input_file_03
53
- e = assert_raise(RuntimeError) {
54
- p = Podgraph::Posterous.new(@testdir+'/garbage_03.html',
53
+ e = assert_raises(RuntimeError) {
54
+ p = Podgraph::Posterous.new(@u, @testdir+'/garbage_03.html',
55
55
  @to, @from, 'related')
56
56
  }
57
57
  assert_match(/body is empty or filled with nonsence/, e.message)
58
58
  end
59
59
 
60
60
  def test_invalid_input_file_04
61
- e = assert_raise(RuntimeError) {
62
- p = Podgraph::Posterous.new(@testdir+'/garbage_04.html',
61
+ e = assert_raises(RuntimeError) {
62
+ p = Podgraph::Posterous.new(@u, @testdir+'/garbage_04.html',
63
63
  @to, @from, 'related')
64
64
  mail = p.generate()
65
65
  }
@@ -69,25 +69,26 @@ class TestMime < Test::Unit::TestCase
69
69
 
70
70
  # NOTE: run
71
71
  #
72
- # % ../bin/podgraph -S simple.html | grep -v -e ^Date: -e ^Message-ID: -e '^user-agent:'|md5
72
+ # ../bin/podgraph -S simple.html | grep -v -e ^To: -e '^Date:' -e ^Message-ID: -e '^user-agent:'|md5
73
73
  #
74
- # to get a new hash for this test
74
+ # to get a new hash for this test.
75
75
  def test_simple
76
- p = Podgraph::Posterous.new(@testdir+'/simple.html', @to, @from, 'related')
77
- mail = p.generate().to_s
76
+ p = Podgraph::Posterous.new(@u, @testdir+'/simple.html', @to, @from, 'related')
77
+ mail = p.generate.to_s
78
78
  mail.sub!(/^Date: .+$\n/, '')
79
+ mail.sub!(/^To: .+$\n/, '')
79
80
  mail.sub!(/^Message-ID: .+$\n/, '')
80
81
  mail.sub!(/^user-agent: .+$\n/, '')
81
82
  # p mail
82
83
  # puts mail
83
- assert_equal('ffaf6609a4544258e59dfde9f766820f',
84
- Digest::MD5.hexdigest("#{mail}\n") ) # don't forget a newline!
84
+ assert_equal('c7ac3a5797496efd323c7017c4516cb1',
85
+ Digest::MD5.hexdigest(mail + "\n"))
85
86
  end
86
87
 
87
88
  def test_related
88
89
  p = mail = nil
89
90
  Dir.chdir(@testdir) do
90
- p = Podgraph::Posterous.new(@testdir+'/related.html', @to, @from, 'related')
91
+ p = Podgraph::Posterous.new(@u, @testdir+'/related.html', @to, @from, 'related')
91
92
  mail = p.generate()
92
93
  end
93
94
  assert_equal(mail.multipart?, true)
@@ -98,7 +99,7 @@ class TestMime < Test::Unit::TestCase
98
99
 
99
100
  # html
100
101
  assert_equal(mail.parts[0].content_type, "text/html; charset=UTF-8")
101
- assert_not_equal(mail.parts[0].content_disposition, "inline")
102
+ refute_equal(mail.parts[0].content_disposition, "inline")
102
103
  assert_equal(mail.parts[1].content_disposition, "inline")
103
104
  assert_equal(mail.parts[2].content_disposition, "inline")
104
105
 
@@ -112,7 +113,7 @@ class TestMime < Test::Unit::TestCase
112
113
  def test_mixed
113
114
  p = mail = nil
114
115
  Dir.chdir(@testdir) do
115
- p = Podgraph::Posterous.new('related.html', @to, @from, 'mixed')
116
+ p = Podgraph::Posterous.new(@u, 'related.html', @to, @from, 'mixed')
116
117
  mail = p.generate()
117
118
  end
118
119
  assert_equal(mail.multipart?, true)
@@ -124,8 +125,8 @@ class TestMime < Test::Unit::TestCase
124
125
  # html
125
126
  assert_equal(mail.parts[0].content_type, "text/html; charset=UTF-8")
126
127
  assert_equal(mail.parts[0].content_disposition, "inline")
127
- assert_not_equal(mail.parts[1].content_disposition, "inline")
128
- assert_not_equal(mail.parts[2].content_disposition, "inline")
128
+ refute_equal(mail.parts[1].content_disposition, "inline")
129
+ refute_equal(mail.parts[2].content_disposition, "inline")
129
130
  end
130
131
 
131
132
  end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: podgraph
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 3
9
- version: 0.0.3
4
+ prerelease:
5
+ version: 0.0.5
10
6
  platform: ruby
11
7
  authors:
12
8
  - Alexander Gromnitsky
@@ -14,38 +10,31 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-09-07 00:00:00 +03:00
18
- default_executable:
13
+ date: 2011-04-18 00:00:00 Z
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: mail
22
17
  prerelease: false
23
18
  requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
24
20
  requirements:
25
- - - "="
21
+ - - ~>
26
22
  - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 1
30
- - 3
31
- version: 2.1.3
23
+ version: 2.2.17
32
24
  type: :runtime
33
25
  version_requirements: *id001
34
26
  - !ruby/object:Gem::Dependency
35
- name: activesupport
27
+ name: git
36
28
  prerelease: false
37
29
  requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
38
31
  requirements:
39
32
  - - ">="
40
33
  - !ruby/object:Gem::Version
41
- segments:
42
- - 3
43
- - 0
44
- - 0
45
- version: 3.0.0
46
- type: :runtime
34
+ version: 1.2.5
35
+ type: :development
47
36
  version_requirements: *id002
48
- description:
37
+ description: Adequately scans XHTML for local inline images and appends them to the mail.
49
38
  email: alexander.gromnitsky@gmail.com
50
39
  executables:
51
40
  - podgraph
@@ -54,33 +43,38 @@ extensions: []
54
43
  extra_rdoc_files: []
55
44
 
56
45
  files:
57
- - lib/podgraph/posterous.rb
58
- - bin/podgraph
59
46
  - LICENSE
60
- - Rakefile
47
+ - NEWS
61
48
  - README.rdoc
49
+ - Rakefile
62
50
  - TODO
63
- - NEWS
51
+ - bin/podgraph
52
+ - lib/podgraph/meta.rb
53
+ - lib/podgraph/posterous.rb
54
+ - lib/podgraph/trestle.rb
55
+ - test/.document
56
+ - test/blue.png
57
+ - test/config.yaml
58
+ - test/empty.html
59
+ - test/garbage_01.html
60
+ - test/garbage_02.html
61
+ - test/garbage_03.html
62
+ - test/garbage_04.html
63
+ - test/helper.rb
64
+ - test/helper_trestle.rb
64
65
  - test/mechanical-turk/1.html
65
66
  - test/mechanical-turk/2.html
66
- - test/mechanical-turk/sun.jpg
67
67
  - test/mechanical-turk/3.html
68
- - test/mechanical-turk/config.yaml
69
68
  - test/mechanical-turk/Baby-Bunnie.jpg
69
+ - test/mechanical-turk/config.yaml
70
+ - test/mechanical-turk/sun.jpg
70
71
  - test/nosubject.html
71
- - test/ts_mime.rb
72
- - test/empty.html
72
+ - test/rake_git.rb
73
73
  - test/related.html
74
- - test/config.yaml
75
- - test/blue.png
76
- - test/garbage_01.html
77
- - test/garbage_02.html
78
74
  - test/simple.html
79
- - test/garbage_03.html
80
- - test/garbage_04.html
75
+ - test/test_mime.rb
81
76
  - test/yellow.png
82
- has_rdoc: true
83
- homepage:
77
+ homepage: http://github.com/gromnitsky/podgraph
84
78
  licenses: []
85
79
 
86
80
  post_install_message:
@@ -90,26 +84,23 @@ rdoc_options:
90
84
  require_paths:
91
85
  - lib
92
86
  required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
93
88
  requirements:
94
89
  - - ">="
95
90
  - !ruby/object:Gem::Version
96
- segments:
97
- - 1
98
- - 9
99
- version: "1.9"
91
+ version: 1.9.2
100
92
  required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
101
94
  requirements:
102
95
  - - ">="
103
96
  - !ruby/object:Gem::Version
104
- segments:
105
- - 0
106
97
  version: "0"
107
98
  requirements: []
108
99
 
109
100
  rubyforge_project:
110
- rubygems_version: 1.3.6
101
+ rubygems_version: 1.7.2
111
102
  signing_key:
112
103
  specification_version: 3
113
104
  summary: Creates a MIME mail from a XHTML source and delivers it to Posterous.com.
114
105
  test_files:
115
- - test/ts_mime.rb
106
+ - test/test_mime.rb