wagon 0.9.5 → 0.10.0

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