wagon 0.9.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ spec/user.dat
23
+ *.pdf
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Devin Christensen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = Wagon
2
+
3
+ Provided a valid lds.org username and password Wagon will download the information and pictures from the "Photo Directory" page and compile it into a convenient PDF.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Devin Christensen. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "wagon"
8
+ gem.summary = %Q{Create a PDF from the lds.org ward Photo Directory.}
9
+ gem.description = %Q{Provided a valid lds.org username and password, Wagon will download all the information from the Photo Directory page and compile it into a convenient PDF.}
10
+ gem.email = "devin@threetrieslater.com"
11
+ gem.homepage = "http://github.com/threetrieslater/wagon"
12
+ gem.authors = ["Devin Christensen"]
13
+ gem.bindir = 'bin'
14
+ gem.add_dependency "nokogiri", ">= 1.4.0"
15
+ gem.add_dependency "highline", ">= 1.5.1"
16
+ gem.add_dependency "prawn", ">= 0.5.1"
17
+ gem.add_development_dependency "rspec", ">= 1.2.9"
18
+ gem.add_development_dependency "yard", ">= 0"
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
24
+ end
25
+
26
+ require 'spec/rake/spectask'
27
+ Spec::Rake::SpecTask.new(:spec) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.spec_files = FileList['spec/**/*_spec.rb']
30
+ end
31
+
32
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
33
+ spec.libs << 'lib' << 'spec'
34
+ spec.pattern = 'spec/**/*_spec.rb'
35
+ spec.rcov = true
36
+ end
37
+
38
+ task :spec => :check_dependencies
39
+
40
+ task :default => :spec
41
+
42
+ begin
43
+ require 'yard'
44
+ YARD::Rake::YardocTask.new
45
+ rescue LoadError
46
+ task :yardoc do
47
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
48
+ end
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.9.0
data/bin/wagon ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # == Synopsis
4
+ # Create a PDF from your wards photo directory on lds.org
5
+ #
6
+ # == Examples
7
+ # Output a file named "photo_directory.pdf" to the current directory.
8
+ # wagon
9
+ #
10
+ # Other examples:
11
+ # wagon --title="Ward Menu"
12
+ #
13
+ # == Usage
14
+ # wagon [options] [output_file]
15
+ #
16
+ # == Options
17
+ # -h, --help Displays help message
18
+ # -v, --version Display the version, then exit
19
+ # -V, --verbose Verbose output
20
+ # -t, --title Override the default title with your own
21
+ # -r, --rows Number of rows per page (default is 6)
22
+ # -c, --columns Number of columns per page (default is 7)
23
+ # -p, --padding Padding between households (default is 2)
24
+ # -f, --font-size Primary font size (default is 8)
25
+ # --page-numbers Include page numbers in the footer, e.g. (1 of 3)
26
+ # --date Include the current date in the footer
27
+ # --no-picture Do not include pictures
28
+ # --no-address Do not include street addresses
29
+ # --no-phone Do not include phone numbers
30
+ # --no-email Do not include email addresses
31
+ #
32
+ # == Copyright
33
+ # Copyright (c) 2009 Devin Christensen. Licensed under the MIT License:
34
+ # http://www.opensource.org/licenses/mit-license.php
35
+
36
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
37
+
38
+ require 'optparse'
39
+ require 'rdoc/usage'
40
+ require 'ostruct'
41
+ require 'wagon'
42
+ require 'highline/import'
43
+
44
+ class WagonApp
45
+ def initialize(arguments, stdin)
46
+ @arguments = arguments
47
+ @stdin = stdin
48
+ @options = OpenStruct.new()
49
+
50
+ # Set defaults
51
+ @options.verbose = false
52
+ @options.title = nil
53
+ @options.rows = 6
54
+ @options.columns = 7
55
+ @options.padding = 2
56
+ @options.font_size = 8
57
+ @options.page_numbers = false
58
+ @options.include_date = false
59
+ @options.picture = true
60
+ @options.address = true
61
+ @options.phone_number = true
62
+ @options.email = true
63
+ @options.output_file = "./photo_directory.pdf"
64
+ end
65
+
66
+ def run
67
+ if arguments_valid?
68
+ puts "Start at #{DateTime.now}\n\n" if @options.verbose
69
+
70
+ output_options if @options.verbose # [Optional]
71
+
72
+ process
73
+
74
+ puts "\nFinished in #{DateTime.now}" if @options.verbose
75
+
76
+ else
77
+ output_usage
78
+ end
79
+
80
+ end
81
+
82
+ protected
83
+ def arguments_valid?
84
+ # Specify options
85
+ opts = OptionParser.new
86
+ opts.on('-v', '--version') { output_version ; exit 0 }
87
+ opts.on('-h', '--help') { output_help }
88
+ opts.on('-V', '--verbose') { @options.verbose = true }
89
+ opts.on('-t', '--title=TITLE') { |title| @options.title = title }
90
+ opts.on('-r', '--rows=ROWS') { |rows| @options.rows = rows }
91
+ opts.on('-c', '--columns=COLUMNS') { |columns| @options.columns = columns }
92
+ opts.on('-p', '--padding=PADDING') { |padding| @options.padding = padding }
93
+ opts.on('-f', '--font-size=SIZE') { |size| @options.font_size = size }
94
+ opts.on('--page-numbers') { @options.page_numbering = true }
95
+ opts.on('--date') { @options.include_date = true }
96
+ opts.on('--no-picture') { @options.picture = false }
97
+ opts.on('--no-address') { @options.address = false }
98
+ opts.on('--no-phone') { @options.phone_number = false }
99
+ opts.on('--no-email') { @options.email = false }
100
+
101
+ opts.parse!(@arguments) rescue return false
102
+ @options.output_file = @arguments.last unless @arguments.empty?
103
+
104
+ true
105
+ end
106
+
107
+ def output_options
108
+ puts "Options:\n"
109
+
110
+ @options.marshal_dump.each do |name, val|
111
+ puts " #{name} = #{val}"
112
+ end
113
+ end
114
+
115
+ def output_help
116
+ output_version
117
+ RDoc::usage()
118
+ end
119
+
120
+ def output_usage
121
+ RDoc::usage('usage') # gets usage from comments above
122
+ end
123
+
124
+ def output_version
125
+ puts "#{File.basename(__FILE__)} version #{Wagon::VERSION}"
126
+ end
127
+
128
+ def process
129
+ username = ask("What is your lds.org username? ")
130
+ password = ask("What is your lds.org password? ") { |q| q.echo = "*" }
131
+
132
+ user = Wagon::connect(username, password)
133
+
134
+ puts "\nAlright, we're in!"
135
+ puts "I'm gonna go ahead and create that PDF for ya now."
136
+ puts "It might take a few minutes to gather all the info"
137
+ puts "so grab a crisp cool beverage, sit back and relax."
138
+ puts "I'll take it from here."
139
+
140
+ directory = user.ward.to_pdf( @options.marshal_dump )
141
+ directory.render_file(@options.output_file)
142
+
143
+ puts "\nFinished. Enjoy.\n"
144
+
145
+ rescue Wagon::AuthenticationFailure
146
+ puts "\nThe username and password combination you entered is invalid."
147
+ rescue
148
+ if @options.verbose
149
+ raise
150
+ else
151
+ puts "\nI encountered an unexpected problem, and I don't know what to do. :("
152
+ end
153
+ end
154
+ end
155
+
156
+ app = WagonApp.new(ARGV, STDIN)
157
+ app.run
data/cache/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.cache
Binary file
data/lib/wagon.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Wagon
2
+ BASE_PATH = File.join(File.dirname(__FILE__), '..')
3
+ VERSION = open(File.join(BASE_PATH, 'VERSION')).read()
4
+
5
+ def self.connect(username, password)
6
+ Connection.new(username, password)
7
+ end
8
+ end
9
+
10
+ require 'wagon/page'
11
+ require 'wagon/connection'
@@ -0,0 +1,35 @@
1
+ module Wagon
2
+ class Address
3
+ CITY_STATE_ZIP = %r/^(\D+), (\D+)?\s*(\d+(-\d+)?)?$/
4
+
5
+ attr_reader :street, :city, :state, :zip, :country
6
+
7
+ def self.extract_from_string(string)
8
+ parts = string.split("\n").collect(&:strip).delete_if(&:empty?)
9
+ street = city = state = zip = country = nil
10
+
11
+ parts.delete_if do |part|
12
+ next unless part =~ CITY_STATE_ZIP
13
+ city, state, zip = $1, ($2 || '').strip(), $3; true
14
+ end
15
+
16
+ self.new(parts.shift, city, state, zip, parts.shift)
17
+ end
18
+
19
+ def initialize(street, city, state, zip, country)
20
+ @street, @city, @state, @zip, @country = street, city, state, zip, country
21
+ end
22
+
23
+ def to_s
24
+ [street, [[city, state].compact.join(", "), zip, country.to_s.empty? ? nil : "(#{country})"].compact.join(" ")].compact.join("\n")
25
+ end
26
+
27
+ def ==(other)
28
+ street == other.street &&
29
+ city == other.city &&
30
+ state == other.state &&
31
+ zip == other.zip &&
32
+ country == other.country
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,81 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'digest/sha1'
5
+ require 'wagon/ward'
6
+
7
+ module Wagon
8
+
9
+ class AuthenticationFailure < StandardError; end
10
+
11
+ class Connection
12
+ HOST = 'secure.lds.org'
13
+ LOGIN_PATH = '/units/a/login/1,21568,779-1,00.html?URL='
14
+
15
+ def initialize(username, password)
16
+ response = post(LOGIN_PATH, 'username' => username, 'password' => password)
17
+ @cookies = response['set-cookie']
18
+ @home_path = URI.parse(response['location']).path
19
+
20
+ raise AuthenticationFailure.new("Invalid username and/or password") unless @cookies
21
+ end
22
+
23
+ def home_path
24
+ @home_path
25
+ end
26
+
27
+ def ward
28
+ @ward ||= Ward.new(self, home_path)
29
+ end
30
+
31
+ def get(path)
32
+ Connection.perform_caching? ? get_with_caching(path) : get_without_caching(path)
33
+ end
34
+
35
+ def get_without_caching(path)
36
+ _http.request(Net::HTTP::Get.new(path, {'Cookie' => @cookies || ''})).body
37
+ end
38
+
39
+ def get_with_caching(path)
40
+ cache_path = File.join(Wagon::BASE_PATH, 'cache', Digest::SHA1.hexdigest(path) + ".cache")
41
+ return open(cache_path).read if File.exists?(cache_path)
42
+ open(cache_path, "w").write(data = get_without_caching(path))
43
+ data
44
+ end
45
+
46
+ def self.perform_caching?
47
+ @@perform_caching ||= true
48
+ end
49
+
50
+ def self.perform_caching(true_or_false)
51
+ @@perform_caching = true_or_false
52
+ end
53
+
54
+ def post(path, data)
55
+ request = Net::HTTP::Post.new(path, {'Cookie' => @cookies || ''})
56
+ request.set_form_data(data)
57
+ _http.request(request)
58
+ end
59
+
60
+ def _dump(depth)
61
+ Marshal.dump([@cookies, @home_path])
62
+ end
63
+
64
+ def self._load(string)
65
+ attributes = Marshal.restore(string)
66
+ connection = Connection.allocate()
67
+ connection.instance_variable_set(:@cookies, attributes.shift)
68
+ connection.instance_variable_set(:@home_path, attributes.shift)
69
+ connection
70
+ end
71
+
72
+ private
73
+ def _http
74
+ return @http unless @http.nil?
75
+ @http = Net::HTTP.new(HOST, 443)
76
+ @http.use_ssl = true
77
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
78
+ @http
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,72 @@
1
+ require 'wagon/photo_directory'
2
+ require 'prawn'
3
+ require 'stringio'
4
+
5
+ module Wagon
6
+ class Directory < Page
7
+ def photo_directory_path
8
+ return @photo_directory_path unless @photo_directory_path.nil?
9
+
10
+ self.at('a.linknoline[href^="javascript:confirm_photo"]')['href'].match(/^javascript:confirm_photo\('(.*)'\);$/)
11
+ @photo_directory_path = $1
12
+ end
13
+
14
+ def photo_directory
15
+ @photo_directory ||= PhotoDirectory.new(connection, photo_directory_path)
16
+ end
17
+
18
+ def households
19
+ @households ||= photo_directory.households.sort
20
+ end
21
+
22
+ def members
23
+ households.collect(&:members).flatten()
24
+ end
25
+
26
+ def to_pdf(options = {})
27
+ options = {:columns => 7, :rows => 6, :padding => 2, :font_size => 8, :address => true, :phone_number => true, :email => true}.merge(options)
28
+
29
+ Prawn::Document.new(:skip_page_creation => true, :left_margin => 10, :right_margin => 10, :top_margin => 20, :bottom_margin => 10) do |pdf|
30
+ columns = options[:columns].to_f
31
+ rows = options[:rows].to_f
32
+ padding = options[:padding].to_f
33
+ grid_width = pdf.bounds.width / columns
34
+ grid_height = pdf.bounds.height / rows
35
+ box_width = grid_width - (padding * 2)
36
+ box_height = grid_height - (padding * 2)
37
+ pages = (households.size.to_f / (columns * rows)).ceil()
38
+ info_lines = 1 + [:address, :phone_number, :email].inject(0) { |sum, item| sum += item ? 1 : 0 }
39
+ pdf.font_size = options[:font_size].to_i
40
+
41
+ (0...pages).each do |page|
42
+ pdf.start_new_page
43
+ (0...rows).each do |row|
44
+ y = pdf.bounds.top - row*grid_height
45
+ (0...columns).each do |column|
46
+ break if (index = page*rows*columns+row*columns+column) >= households.size
47
+ household = households[index]
48
+ x = pdf.bounds.left + column*grid_width
49
+ pdf.bounding_box([x, y], :width => grid_width, :height => grid_height) do
50
+ pdf.bounding_box([pdf.bounds.left + padding, pdf.bounds.top - padding], :width => box_width, :height => box_height) do
51
+ information = []
52
+ information.push(household.name)
53
+ information.push(*household.address.street) if options[:address]
54
+ information.push(household.phone_number) if options[:phone_number]
55
+ information.push(household.members.first.email) if options[:email]
56
+
57
+ pdf.image(household.has_image? ? StringIO.new(household.image_data) : './extra/placeholder.jpg',
58
+ :position => :center, :fit => [box_width, box_height - (padding*2 + pdf.font.height*info_lines)] )
59
+
60
+ pdf.move_down(padding)
61
+ information.compact.each do |line|
62
+ pdf.text(line, :align => :center, :size => pdf.font_size.downto(1).detect() { |size| pdf.width_of(line.to_s, :size => size) <= box_width })
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,63 @@
1
+ require 'wagon/address'
2
+ require 'wagon/phone_number'
3
+ require 'wagon/member'
4
+
5
+ require 'base64'
6
+
7
+ module Wagon
8
+ class Household
9
+ attr_reader :connection
10
+ attr_writer :name
11
+ attr_accessor :address, :phone_number, :image_path, :members
12
+
13
+ def initialize(connection)
14
+ @members = []
15
+ @connection = connection
16
+ end
17
+
18
+ def name
19
+ self.individual? ? "#{members.first.name} #{@name}" : "#{@name} Household"
20
+ end
21
+
22
+ def reversed_name
23
+ self.individual? ? "#{@name}, #{members.first.name}" : name
24
+ end
25
+
26
+ def individual?
27
+ members.count == 1
28
+ end
29
+
30
+ def has_image?
31
+ !image_path.to_s.empty?
32
+ end
33
+
34
+ def image_data
35
+ @image_data ||= image_path.to_s.empty? ? "" : connection.get(image_path)
36
+ end
37
+
38
+ def <=>(other)
39
+ if has_image? == other.has_image?
40
+ reversed_name <=> other.reversed_name
41
+ else
42
+ has_image? ? -1 : 1
43
+ end
44
+ end
45
+
46
+ def self.create_from_td(connection, td)
47
+ Household.new(connection).instance_eval do
48
+ name_element, phone_element, *member_elements = *td.search('table > tr > td.eventsource[width="45%"] > table > tr > td.eventsource')
49
+ @address = Address.extract_from_string(td.search('table > tr > td.eventsource[width="25%"]').inner_text)
50
+ @image_path = td.at('table > tr > td.eventsource[width="30%"] > img')['src'] rescue nil
51
+ @name = name_element.inner_text
52
+ @phone_number = PhoneNumber.extract_from_string(phone_element.inner_text)
53
+
54
+ member_elements.each_slice(2) do |name_and_email|
55
+ name, email = *name_and_email.collect { |element| element.inner_text.gsub(/\302\240/, '').strip() }
56
+ @members << Member.new(self, name, email)
57
+ end
58
+
59
+ self
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,11 @@
1
+ class Member
2
+ attr_reader :household, :name, :email
3
+
4
+ def initialize(household, name, email)
5
+ @household, @name, @email = household, name, email
6
+ end
7
+
8
+ def to_s
9
+ [name, household.name, email.to_s.empty? ? nil : "<#{email}>"].compact.join(" ")
10
+ end
11
+ end
data/lib/wagon/page.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'nokogiri'
2
+
3
+ module Wagon
4
+ class Page
5
+ attr_reader :connection
6
+
7
+ def initialize(connection, url)
8
+ @connection, @url = connection, url
9
+ end
10
+
11
+ def source
12
+ @source ||= Nokogiri::HTML(get(@url))
13
+ end
14
+
15
+ def get(*args)
16
+ connection.get(*args)
17
+ end
18
+
19
+ def post(*args)
20
+ connection.post(*args)
21
+ end
22
+
23
+ def method_missing(method, *args, &block)
24
+ unless source.respond_to?(method)
25
+ super(method, *args, &block)
26
+ else
27
+ source.send(method, *args, &block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module Wagon
2
+ class PhoneNumber
3
+ attr_reader :type, :value
4
+
5
+ def self.extract_from_string(string)
6
+ string.strip =~ /([\)\(\+\s\-\d]+)(\((.*)\))?$/
7
+ self.new($3 || 'Home', $1.strip)
8
+ end
9
+
10
+ def initialize(type, value)
11
+ @type, @value = type, value
12
+ end
13
+
14
+ def ==(other)
15
+ type == other.type &&
16
+ value == other.value
17
+ end
18
+
19
+ def to_s
20
+ self.value
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'wagon/household'
2
+
3
+ module Wagon
4
+ class PhotoDirectory < Page
5
+ def households
6
+ @households ||= _parse_households
7
+ end
8
+
9
+ def members
10
+ households.collect(&:members).flatten()
11
+ end
12
+
13
+ def to_pdf(options)
14
+ Prawn::Document.new() do |pdf|
15
+ households.each do |household|
16
+ pdf.text household.name
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+ def _parse_households
23
+ self.search('body > table > tr > td.eventsource[@width="25%"]').collect do |household_td|
24
+ household = Household.create_from_td(connection, household_td)
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/wagon/ward.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'wagon/directory'
2
+
3
+ module Wagon
4
+ class Ward < Page
5
+ def name
6
+ @name ||= self.at('a.channeltitle[href^="/units/home"]').inner_text.strip
7
+ end
8
+
9
+ def directory_path
10
+ @directory_path ||= self.at('a.directory[href^="/units/a/directory"]')['href']
11
+ end
12
+
13
+ def directory
14
+ @directory ||= Directory.new(connection, directory_path)
15
+ end
16
+
17
+ def households
18
+ directory.households
19
+ end
20
+
21
+ def members
22
+ households.collect(&:members).flatten()
23
+ end
24
+
25
+ def to_pdf(options)
26
+ directory.to_pdf(options)
27
+ end
28
+ end
29
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,35 @@
1
+ BASE_PATH = File.join(File.dirname(__FILE__), '..')
2
+ USER_FILE = File.join(BASE_PATH, 'spec', 'user.dat')
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(BASE_PATH, 'lib'))
6
+
7
+ require 'spec'
8
+ require 'spec/autorun'
9
+ require 'rubygems'
10
+ require 'wagon'
11
+ require 'highline/import'
12
+
13
+ $user = nil
14
+
15
+ def establish_connection
16
+ username = ask("What is your lds.org username? ")
17
+ password = ask("What is your lds.org password? ") { |prompt| prompt.echo = "*" }
18
+
19
+ $user = Wagon::connect(username, password)
20
+ open(USER_FILE, 'w').write(Marshal.dump($user))
21
+ end
22
+
23
+ def restore_connection
24
+ $user = Marshal.restore(open(USER_FILE).read)
25
+ end
26
+
27
+ if File.exists?(USER_FILE)
28
+ restore_connection()
29
+ else
30
+ establish_connection()
31
+ end
32
+
33
+ Spec::Runner.configure do |config|
34
+
35
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe "Wagon::Directory" do
4
+
5
+ before(:each) do
6
+ @page = Wagon::Directory.new($user, $user.ward.directory_path)
7
+ end
8
+
9
+ it "should find the photo directory link" do
10
+ @page.photo_directory_path.should_not be_nil
11
+ @page.photo_directory_path.should match(%r{^/units/a/directory/photoprint})
12
+ end
13
+
14
+ it "should be able to generate a pdf" do
15
+ @page.to_pdf.render_file("./photo_directory.pdf")
16
+ end
17
+
18
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe "Wagon::PhotoDirectory" do
4
+
5
+ before(:each) do
6
+ @page = Wagon::PhotoDirectory.new($user, $user.ward.directory.photo_directory_path)
7
+ end
8
+
9
+ it "should parse out the households correctly" do
10
+ @page.households.should have_at_least(10).items
11
+ end
12
+
13
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe "Wagon::Ward" do
4
+
5
+ before(:each) do
6
+ @page = Wagon::Ward.new($user, $user.home_path)
7
+ end
8
+
9
+ it "should have a name" do
10
+ @page.name.to_s.should_not be_empty
11
+ end
12
+
13
+ it "should find the directory link" do
14
+ @page.directory_path.should_not be_nil
15
+ @page.directory_path.should match(%r{^/units/a/directory})
16
+ end
17
+
18
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Wagon" do
4
+
5
+ before(:each) do
6
+ @user = $user
7
+ end
8
+
9
+ it "should be connected" do
10
+ @user.should_not be_nil
11
+ @user.home_path.should_not be_nil
12
+ end
13
+
14
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wagon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Devin Christensen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-07 00:00:00 -07:00
13
+ default_executable: wagon
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nokogiri
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.4.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: highline
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: prawn
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.1
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: rspec
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.2.9
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ description: Provided a valid lds.org username and password, Wagon will download all the information from the Photo Directory page and compile it into a convenient PDF.
66
+ email: devin@threetrieslater.com
67
+ executables:
68
+ - wagon
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - LICENSE
73
+ - README.rdoc
74
+ files:
75
+ - .document
76
+ - .gitignore
77
+ - LICENSE
78
+ - README.rdoc
79
+ - Rakefile
80
+ - VERSION
81
+ - bin/wagon
82
+ - cache/.gitignore
83
+ - extra/placeholder.jpg
84
+ - lib/wagon.rb
85
+ - lib/wagon/address.rb
86
+ - lib/wagon/connection.rb
87
+ - lib/wagon/directory.rb
88
+ - lib/wagon/household.rb
89
+ - lib/wagon/member.rb
90
+ - lib/wagon/page.rb
91
+ - lib/wagon/phone_number.rb
92
+ - lib/wagon/photo_directory.rb
93
+ - lib/wagon/ward.rb
94
+ - spec/spec.opts
95
+ - spec/spec_helper.rb
96
+ - spec/wagon/directory_spec.rb
97
+ - spec/wagon/photo_directory_spec.rb
98
+ - spec/wagon/ward_spec.rb
99
+ - spec/wagon_spec.rb
100
+ has_rdoc: true
101
+ homepage: http://github.com/threetrieslater/wagon
102
+ licenses: []
103
+
104
+ post_install_message:
105
+ rdoc_options:
106
+ - --charset=UTF-8
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ version:
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: "0"
120
+ version:
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.5
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Create a PDF from the lds.org ward Photo Directory.
128
+ test_files:
129
+ - spec/spec_helper.rb
130
+ - spec/wagon/directory_spec.rb
131
+ - spec/wagon/photo_directory_spec.rb
132
+ - spec/wagon/ward_spec.rb
133
+ - spec/wagon_spec.rb