podgraph 0.0.3 → 0.0.5

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.
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