wagon 0.9.5 → 0.10.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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.5
1
+ 0.10.0
data/bin/wagon CHANGED
@@ -128,7 +128,7 @@ class WagonApp
128
128
 
129
129
  directory = user.ward.to_pdf( @options.marshal_dump )
130
130
  directory.render_file(@options.output_file)
131
-
131
+
132
132
  puts "\nFinished. Enjoy.\n"
133
133
 
134
134
  rescue Wagon::AuthenticationFailure
data/lib/wagon/address.rb CHANGED
@@ -2,7 +2,7 @@ module Wagon
2
2
  class Address
3
3
  CITY_STATE_ZIP = %r/^(\D+), (\D+)?\s*(\d+(-\d+)?)?$/
4
4
 
5
- attr_reader :street, :city, :state, :zip, :country
5
+ attr_reader :city, :state, :zip, :country
6
6
 
7
7
  def self.extract_from_string(string)
8
8
  parts = string.split("\n").collect(&:strip).delete_if(&:empty?)
@@ -20,6 +20,11 @@ module Wagon
20
20
  @street, @city, @state, @zip, @country = street, city, state, zip, country
21
21
  end
22
22
 
23
+ def street
24
+ #601 N. Monterey Drive Apartment K
25
+ @street.to_s.gsub(/apartment/i, 'Apt.').gsub(/drive/i, 'Dr.')
26
+ end
27
+
23
28
  def to_s
24
29
  [street, [[city, state].compact.join(", "), zip, country.to_s.empty? ? nil : "(#{country})"].compact.join(" ")].compact.join("\n")
25
30
  end
@@ -1,20 +1,48 @@
1
1
  require 'net/http'
2
2
  require 'net/https'
3
+ require 'curb'
3
4
  require 'uri'
4
5
  require 'digest/sha1'
5
6
  require 'wagon/ward'
6
7
 
7
8
  module Wagon
8
-
9
9
  class AuthenticationFailure < StandardError; end
10
10
 
11
11
  class Connection
12
12
  HOST = 'secure.lds.org'
13
13
  LOGIN_PATH = '/units/a/login/1,21568,779-1,00.html?URL='
14
- CACHE_PATH = File.join(File.expand_path('~'), '.wagon_cache')
14
+
15
+ # For asynchronous procedures
16
+ @@trigger = ConditionVariable.new
17
+ @@lock = Mutex.new
18
+ @@queue = []
19
+
20
+ (1..30).collect do
21
+ Thread.new do
22
+ http = Net::HTTP.new(HOST, 443)
23
+ http.use_ssl = true
24
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
25
+ http
26
+
27
+ while true
28
+ connection, path, callback = nil, nil, nil
29
+ @@lock.synchronize do
30
+ connection, path, callback = *@@queue.shift
31
+ end
32
+
33
+ if connection
34
+ callback.call(http.request(Net::HTTP::Get.new(path, {'Cookie' => connection.cookies || ''})))
35
+ else
36
+ sleep(0.5)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ attr_reader :cookies
15
43
 
16
44
  def initialize(username, password)
17
- response = post(LOGIN_PATH, 'username' => username, 'password' => password)
45
+ response = _post(LOGIN_PATH, 'username' => username, 'password' => password)
18
46
  @cookies = response['set-cookie']
19
47
  @home_path = URI.parse(response['location']).path
20
48
 
@@ -30,33 +58,17 @@ module Wagon
30
58
  end
31
59
 
32
60
  def get(path)
33
- Connection.perform_caching? ? get_with_caching(path) : get_without_caching(path)
34
- end
35
-
36
- def get_without_caching(path)
37
- _http.request(Net::HTTP::Get.new(path, {'Cookie' => @cookies || ''})).body
61
+ _get(path).body
38
62
  end
39
63
 
40
- def get_with_caching(path)
41
- FileUtils::mkdir(CACHE_PATH) unless File.directory?(CACHE_PATH)
42
- cache_path = File.join(CACHE_PATH, Digest::SHA1.hexdigest(path) + ".cache")
43
- return open(cache_path).read if File.exists?(cache_path)
44
- open(cache_path, "w").write(data = get_without_caching(path))
45
- data
64
+ def get_async(path, &block)
65
+ @@lock.synchronize do
66
+ @@queue.push([self, path, block])
67
+ end
46
68
  end
47
69
 
48
- def self.perform_caching?
49
- @@perform_caching ||= true
50
- end
51
-
52
- def self.perform_caching(true_or_false)
53
- @@perform_caching = true_or_false
54
- end
55
-
56
- def post(path, data)
57
- request = Net::HTTP::Post.new(path, {'Cookie' => @cookies || ''})
58
- request.set_form_data(data)
59
- _http.request(request)
70
+ def expired?
71
+ _head(ward.directory_path).class != Net::HTTPOK
60
72
  end
61
73
 
62
74
  def _dump(depth)
@@ -79,5 +91,25 @@ module Wagon
79
91
  @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
80
92
  @http
81
93
  end
94
+
95
+ def _curl
96
+ @curl ||= Curl::Easy.new do |curl|
97
+ curl.headers = {'Cookie' => @cookies || ''}
98
+ end
99
+ end
100
+
101
+ def _get(path)
102
+ _http.request(Net::HTTP::Get.new(path, {'Cookie' => @cookies || ''}))
103
+ end
104
+
105
+ def _head(path)
106
+ _http.request(Net::HTTP::Head.new(path, {'Cookie' => @cookies || ''}))
107
+ end
108
+
109
+ def _post(path, data)
110
+ request = Net::HTTP::Post.new(path, {'Cookie' => @cookies || ''})
111
+ request.set_form_data(data)
112
+ _http.request(request)
113
+ end
82
114
  end
83
115
  end
@@ -8,23 +8,10 @@ module Wagon
8
8
  @parent
9
9
  end
10
10
 
11
- def photo_directory_path
12
- return @photo_directory_path unless @photo_directory_path.nil?
13
-
14
- self.at('a.linknoline[href^="javascript:confirm_photo"]')['href'].match(/^javascript:confirm_photo\('(.*)'\);$/)
15
- @photo_directory_path = $1
16
- end
17
-
18
- def photo_directory
19
- @photo_directory ||= PhotoDirectory.new(connection, photo_directory_path)
20
- end
21
-
22
11
  def households
23
- @households ||= photo_directory.households.sort
24
- end
25
-
26
- def members
27
- households.collect(&:members).flatten()
12
+ @households ||= self.search('body > table > tr > td.eventsource[@width="25%"]').collect do |household_td|
13
+ household = Household.create_from_td(connection, household_td)
14
+ end.sort
28
15
  end
29
16
 
30
17
  def to_pdf(options = {})
@@ -62,8 +49,9 @@ module Wagon
62
49
  y = pdf.bounds.top - row*grid_height - header_height
63
50
  (0...columns).each do |column|
64
51
  break if (index = page*rows*columns+row*columns+column) >= households.size
65
- household = households[index]
66
52
  x = pdf.bounds.left + column*grid_width
53
+ household = households[index]
54
+
67
55
  pdf.bounding_box([x, y], :width => grid_width, :height => grid_height) do
68
56
  pdf.bounding_box([pdf.bounds.left + padding, pdf.bounds.top - padding], :width => box_width, :height => box_height) do
69
57
  info = []
@@ -6,13 +6,16 @@ require 'base64'
6
6
 
7
7
  module Wagon
8
8
  class Household
9
- attr_reader :connection
10
- attr_writer :name
11
- attr_accessor :address, :phone_number, :image_path, :members
9
+ attr_reader :connection, :address, :phone_number, :image_path, :members
12
10
 
13
- def initialize(connection)
14
- @members = []
15
- @connection = connection
11
+ def initialize(connection, name, address, phone_number, image_path, members)
12
+ @connection, @name, @address, @phone_number, @image_path, @members = connection, name, address, phone_number, image_path, members
13
+
14
+ if has_image?
15
+ @connection.get_async(image_path) do |response|
16
+ @image_data = response.body
17
+ end
18
+ end
16
19
  end
17
20
 
18
21
  def name
@@ -32,7 +35,11 @@ module Wagon
32
35
  end
33
36
 
34
37
  def image_data
35
- @image_data ||= image_path.to_s.empty? ? "" : connection.get(image_path)
38
+ return nil unless has_image?
39
+
40
+ sleep(0.5) while @image_data.nil?
41
+
42
+ @image_data
36
43
  end
37
44
 
38
45
  def <=>(other)
@@ -43,21 +50,26 @@ module Wagon
43
50
  end
44
51
  end
45
52
 
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
53
+ private
54
+ def spawn_download_thread
55
+ @thread ||= Thread.new(image_path) do |path|
56
+ @image_data = connection.get_async(path)
57
+ end
58
+ end
58
59
 
59
- self
60
+ def self.create_from_td(connection, td)
61
+ name_element, phone_element, *member_elements = *td.search('table > tr > td.eventsource[width="45%"] > table > tr > td.eventsource')
62
+ address = Address.extract_from_string(td.search('table > tr > td.eventsource[width="25%"]').inner_text)
63
+ image_path = td.at('table > tr > td.eventsource[width="30%"] > img')['src'] rescue nil
64
+ phone_number = PhoneNumber.extract_from_string(phone_element.inner_text)
65
+ members = []
66
+
67
+ member_elements.each_slice(2) do |name_and_email|
68
+ name, email = *name_and_email.collect { |element| element.inner_text.gsub(/\302\240/, '').strip() }
69
+ members << Member.new(self, name, email)
60
70
  end
71
+
72
+ self.new(connection, name_element.inner_text, address, phone_number, image_path, members)
61
73
  end
62
74
  end
63
75
  end
@@ -4,7 +4,7 @@ module Wagon
4
4
 
5
5
  def self.extract_from_string(string)
6
6
  string.strip =~ /([\)\(\+\s\-\d]+)(\((.*)\))?$/
7
- self.new($3 || 'Home', $1.strip)
7
+ self.new($3 || 'Home', $1.to_s.strip)
8
8
  end
9
9
 
10
10
  def initialize(type, value)
data/lib/wagon/ward.rb CHANGED
@@ -7,7 +7,7 @@ module Wagon
7
7
  end
8
8
 
9
9
  def directory_path
10
- @directory_path ||= self.at('a.directory[href^="/units/a/directory"]')['href']
10
+ @directory_path ||= '/units/a/directory/photoprint/1,10357,605-1-7-197742,00.html'
11
11
  end
12
12
 
13
13
  def directory
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,7 @@ require 'highline/import'
13
13
  $user = nil
14
14
 
15
15
  def establish_connection
16
+ puts "Create a connection for testing: "
16
17
  username = ask("What is your lds.org username? ")
17
18
  password = ask("What is your lds.org password? ") { |prompt| prompt.echo = "*" }
18
19
 
@@ -26,6 +27,11 @@ end
26
27
 
27
28
  if File.exists?(USER_FILE)
28
29
  restore_connection()
30
+
31
+ if $user.expired?
32
+ puts "Previous connection timed out."
33
+ establish_connection()
34
+ end
29
35
  else
30
36
  establish_connection()
31
37
  end
@@ -3,16 +3,20 @@ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
3
3
  describe "Wagon::Directory" do
4
4
 
5
5
  before(:each) do
6
- @page = Wagon::Directory.new($user, $user.ward.directory_path, $user.ward)
6
+ @directory = Wagon::Directory.new($user, $user.ward.directory_path, $user.ward)
7
7
  end
8
8
 
9
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})
10
+ @directory.instance_variable_get(:@url).should_not be_nil
11
+ @directory.instance_variable_get(:@url).should match(%r{^/units/a/directory/photoprint})
12
12
  end
13
13
 
14
14
  it "should be able to generate a pdf" do
15
- @page.to_pdf.render_file("./photo_directory.pdf")
15
+ lambda { @directory.to_pdf.render_file("./photo_directory.pdf") }.should_not raise_error
16
+ end
17
+
18
+ it "should parse out the households correctly" do
19
+ @directory.households.should have_at_least(10).items
16
20
  end
17
21
 
18
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wagon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Devin Christensen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-08 00:00:00 -07:00
12
+ date: 2009-11-13 00:00:00 -07:00
13
13
  default_executable: wagon
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -88,12 +88,10 @@ files:
88
88
  - lib/wagon/member.rb
89
89
  - lib/wagon/page.rb
90
90
  - lib/wagon/phone_number.rb
91
- - lib/wagon/photo_directory.rb
92
91
  - lib/wagon/ward.rb
93
92
  - spec/spec.opts
94
93
  - spec/spec_helper.rb
95
94
  - spec/wagon/directory_spec.rb
96
- - spec/wagon/photo_directory_spec.rb
97
95
  - spec/wagon/ward_spec.rb
98
96
  - spec/wagon_spec.rb
99
97
  has_rdoc: true
@@ -127,6 +125,5 @@ summary: Create a PDF from the lds.org ward Photo Directory.
127
125
  test_files:
128
126
  - spec/spec_helper.rb
129
127
  - spec/wagon/directory_spec.rb
130
- - spec/wagon/photo_directory_spec.rb
131
128
  - spec/wagon/ward_spec.rb
132
129
  - spec/wagon_spec.rb
@@ -1,28 +0,0 @@
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
@@ -1,13 +0,0 @@
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