LBF 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5284874c3a5f3f19e9467153016a4fa96cf2a7d9
4
+ data.tar.gz: 651b62e651a3486a79d320753eeb2e1febb2b8eb
5
+ SHA512:
6
+ metadata.gz: d1f779461701be841101cd36951db59f8d4be2768a7298c1445d6948ed7d5fa9ab596632561798fa77b8b7e5a3007b22fb7a5ed439754fe0d68260c8f3a7ec39
7
+ data.tar.gz: de78338b81f2e7ce4c1044f9d9b1b752aa2095c5a8151790b3dc807b54026233f53a211724e89f0a87597e441ec4144afb5ae03b7a91f0608a334f588000e694
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ go.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lbf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) <year> <copyright holders>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # LBF
2
+
3
+ This is a big ol' pile of nested service objects for interacting with the Look
4
+ Buy Fly SOAP API.
5
+
6
+ **This is a work in progress**
7
+
8
+ #### Todo:
9
+ * Make dependencies leaner (don't require activesupport/all)
10
+ * Tests!
11
+
12
+ ## Installation
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'lbf'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install lbf
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'lbf'
31
+
32
+ client = LBF::Client.new(username: 'lbf_username', # required
33
+ url_id: '42', # required
34
+ password: 'lbf_password', # required
35
+ )
36
+
37
+ request = LBF::Request.new(origin: 'sdf', # required
38
+ destination: 'sna', # required
39
+ ip: '208.73.215.97', # required
40
+ departure_date: Date.tomorrow, # required
41
+ return_date: Date.tomorrow + 7.days # optional
42
+ )
43
+ client.search request
44
+ ```
45
+
46
+ ## Contributing
47
+
48
+ 1. Fork it ( https://github.com/oversee-ffleming/lbf/fork )
49
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
50
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
51
+ 4. Push to the branch (`git push origin my-new-feature`)
52
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lbf.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lbf/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "LBF"
8
+ spec.version = LBF::VERSION
9
+ spec.authors = ["Forrest Fleming"]
10
+ spec.email = ["ffleming@oversee.net"]
11
+ spec.summary = %q{Gem for making requests from LBF API}
12
+ spec.description = %q{Pile of service objects for making requests to the LBF API and its responses}
13
+ spec.homepage = "https://github.com/Oversee/Travel-LBFSoap"
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+ spec.license = 'MIT'
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.7"
21
+
22
+ spec.add_runtime_dependency 'savon', '~> 2.10'
23
+ spec.add_runtime_dependency 'rubyntlm', '0.3.2'
24
+ spec.add_runtime_dependency 'activesupport', '~> 4.1'
25
+
26
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ def deep_fetch(*args)
3
+ key = args.shift
4
+ val = self.fetch(key, nil)
5
+ return val if args.length == 0
6
+ return nil if val.nil? || !val.respond_to?(:deep_fetch)
7
+ val.deep_fetch(*args)
8
+ end
9
+ end
10
+
@@ -0,0 +1,35 @@
1
+ class LBF::Client
2
+ attr_reader :username, :password, :url_id, :wsdl, :cart_path
3
+ def initialize(opts=defaults)
4
+ options = defaults.merge(opts)
5
+ %i(username password url_id).each do |key|
6
+ raise ArgumentError, "Must supply #{key}" unless options.has_key?(key)
7
+ end
8
+ @username = options[:username]
9
+ @password = options[:password]
10
+ @url_id = options[:url_id]
11
+ @wsdl = options[:wsdl]
12
+ end
13
+
14
+ # Searches the LBF API and returns a response object
15
+ # @param [LBF::Request] The Request object that will be sent to the API
16
+ # @return [LBF::Response] The appropriate LBF::Response object
17
+ def search(request=LBF::Request.new)
18
+ client = Savon.client(pretty_print_xml: true, log_level: :debug,
19
+ log: true, wsdl: @wsdl)
20
+ request.client = self
21
+ savon_resp = client.call :afs1, xml: request.to_xml
22
+ response = LBF::Response.new(savon_resp.body)
23
+ response.errors.map {|e| raise e }
24
+ response
25
+ end
26
+
27
+ private
28
+
29
+ def defaults
30
+ {
31
+ wsdl: 'http://webservices.lbftravel.com/services/4.2/ezAirFareService.asmx?WSDL'
32
+ }
33
+ end
34
+
35
+ end
@@ -0,0 +1,2 @@
1
+ class LBF::SearchError < StandardError
2
+ end
@@ -0,0 +1,18 @@
1
+ # This is fare information for LBF. Not all keys from the fare_hash are exposed in the object; see below
2
+ # if we need to expand.
3
+ class LBF::Fare
4
+ def initialize(fare_hash)
5
+ # {:base=>"1653.9400", :tax_and_fees=>"272.4600", :total=>"1926.4000", :sale_total=>"1926.4000",
6
+ # :promo_code=>nil, :promo_discount=>"0.0000", :insurance_total=>"0", :markup=>"0",
7
+ # :tax_and_fees_adult=>"136.2300", :tax_and_fees_child=>"136.2300", :tax_and_fees_infant=>"0",
8
+ # :fare_type=>"P", :insurance_per_traveler=>"0"}
9
+ @base = BigDecimal.new fare_hash[:base]
10
+ @taxes_and_fees = BigDecimal.new fare_hash[:tax_and_fees]
11
+ @total = BigDecimal.new fare_hash[:total]
12
+ @markup = BigDecimal.new fare_hash[:markup]
13
+ @fare_type = fare_hash[:fare_type]
14
+ @discount = BigDecimal.new fare_hash[:promo_discount]
15
+ @promo_code = fare_hash[:promo_code] || 'None'
16
+ @insurance_per_traveler = BigDecimal.new fare_hash[:insurance_per_traveler]
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class LBF::Layover
2
+ attr_reader :duration, :airport
3
+
4
+ # NB: The :duration method (and corresponding ivar) are in seconds
5
+ def initialize(segment_hash)
6
+ @duration = segment_hash[:connection_duration].to_i.minutes
7
+ @airport = segment_hash[:dest]
8
+ @comment = segment_hash[:connection_comment]
9
+ end
10
+ end
11
+
@@ -0,0 +1,8 @@
1
+ # A simple object representing an airplane.
2
+ class LBF::Plane
3
+ attr_reader :name, :code
4
+ def initialize(name, code)
5
+ @name = name
6
+ @code = code.to_i
7
+ end
8
+ end
@@ -0,0 +1,99 @@
1
+ # Each Quote is a proposal from LBF for the requested trip. Its trips are the legs of the flight: there will
2
+ # be one trip in :trips if it is a one-way flight, and two if it is a round-trip flight. Each quote has a
3
+ # pile of IDs that are used to create the appropriate URL string for checkout (which currently doesn't seem
4
+ # to work, but was created according to the API docs).
5
+ #
6
+ # Of particular note are the all_cabins? and nearby_airports? methods. If all_cabins? is true, then the
7
+ # quote will include at least one segment in a cabin type other than that specified in the LBF::Request.
8
+ # Similarly, if :nearby_airports? is true, then either the origin or destination is not that which was
9
+ # requested, but rather an airport that is nearby.
10
+ #
11
+ # If :offline_only? is true, then we can't display actual inforamtion about the trip. We can just display
12
+ # the price and a number to call for booking information.
13
+ class LBF::Quote
14
+ # Has Trip(s) and IDs and Travelers
15
+ attr_reader :arrival, :departure, :fare, :trips, :travelers, :warnings, :cabin_comments,
16
+ :id, :group_id, :session_id, :tickets, :seats_remaining
17
+
18
+ def initialize(quote_hash)
19
+ @hash = quote_hash
20
+ @arrival = DateTime.strptime("#{quote_hash[:arr_dt]} #{quote_hash[:arr_tm]}", '%m/%d/%Y %H%M')
21
+ @departure = DateTime.strptime("#{quote_hash[:dep_dt]} #{quote_hash[:dep_tm]}", '%m/%d/%Y %H%M')
22
+ @fare = LBF::Fare.new quote_hash[:quote_air_fare]
23
+ @trips = trips_from(quote_hash.deep_fetch :quote_air_trips, :quote_air_trip)
24
+ @travelers = travelers_from(quote_hash.deep_fetch :quote_air_travelers, :quote_air_traveler)
25
+ @warnings = warnings_from(quote_hash[:warning])
26
+ @cabin_comments = cabin_comments_from(quote_hash[:cabin_comments])
27
+ @id = quote_hash[:air_quote_id]
28
+ @group_id = quote_hash[:session_air_id]
29
+ @session_id = quote_hash[:visit_session_id]
30
+ @tickets = quote_hash[:tickets].to_i
31
+ @seats_remaining = quote_hash[:seats_remaining].to_i
32
+ @all_cabins = quote_hash[:cabin_indicator].to_i == 1
33
+ @international = !!quote_hash[:international]
34
+ @nearby_airports = !!quote_hash[:nearby_airport_indicator]
35
+ @offline_only = !!quote_hash[:offline_airline_indicator]
36
+ @tournet = !!quote_hash[:tournet_indicator]
37
+ end
38
+
39
+ def to_h
40
+ @hash
41
+ end
42
+
43
+ def query_string
44
+ "?AirSID=#{group_id}&FARE=#{id}&SesnID=#{session_id}"
45
+ end
46
+
47
+ def tournet?
48
+ @tournet
49
+ end
50
+
51
+ def all_cabins?
52
+ @all_cabins
53
+ end
54
+
55
+ def online?
56
+ !offline_only?
57
+ end
58
+
59
+ def offline_only?
60
+ @offline_only
61
+ end
62
+
63
+ def international?
64
+ @international
65
+ end
66
+
67
+ def domestic?
68
+ !international?
69
+ end
70
+
71
+ private
72
+
73
+ def cabin_comments_from(comments_str)
74
+ return '' if comments_str.nil?
75
+ comments_str.to_s
76
+ end
77
+
78
+ # The API doc don't specify how this works, so I'm assuming it's the same as the comments field.
79
+ def warnings_from(warning_str)
80
+ return '' if warning_str.nil?
81
+ warning_str.to_s
82
+ end
83
+
84
+ # The appropriate deep_fetch can return either a hash or an array of hashes,
85
+ # so we have to handle that in this method
86
+ def trips_from(trip_arr)
87
+ return [] if trip_arr.nil?
88
+ trip_arr = [trip_arr].flatten
89
+ trip_arr.map {|t| LBF::Trip.new(t)}
90
+ end
91
+
92
+ # The appropriate deep_fetch can return either a hash or an array of hashes,
93
+ # so we have to handle that in this method
94
+ def travelers_from(trav_arr)
95
+ return [] if trav_arr.nil?
96
+ trav_arr = [trav_arr].flatten
97
+ trav_arr.map {|t| LBF::Traveler.new(t)}
98
+ end
99
+ end
@@ -0,0 +1,130 @@
1
+ # This class just creates a (very specific) XML document with the appropriate request information to send
2
+ # to the LBF API.
3
+ class LBF::Request
4
+ AIRPORT_METHODS = %i(origin destination)
5
+ INT_METHODS = %i(adults children infants)
6
+ DATE_METHODS = %i(departure_date return_date)
7
+ OTHER_METHODS = %i(cabin ip)
8
+ ALL_METHODS = (AIRPORT_METHODS + INT_METHODS + DATE_METHODS + OTHER_METHODS)
9
+ CABINS = {coach: 'Y', business: 'C', first_class: 'F'}
10
+
11
+ attr_reader *ALL_METHODS
12
+ attr_accessor :client
13
+
14
+ AIRPORT_METHODS.each do |meth|
15
+ define_method("#{meth}=".to_sym) do |arg|
16
+ raise ArgumentError, "Argument must be a 3-letter airport code" unless arg =~ /[a-zA-Z]{3}/
17
+ instance_variable_set("@#{meth}", arg.upcase)
18
+ end
19
+ end
20
+
21
+ INT_METHODS.each do |meth|
22
+ define_method("#{meth}=".to_sym) do |arg|
23
+ raise ArgumentError, "Argument must be an Integer" unless arg.is_a?(Integer)
24
+ instance_variable_set("@#{meth}", arg)
25
+ end
26
+ end
27
+
28
+ DATE_METHODS.each do |meth|
29
+ define_method("#{meth}=".to_sym) do |arg|
30
+ raise ArgumentError, "Date must respond to :strftime" unless arg.respond_to?(:strftime)
31
+ instance_variable_set("@#{meth}", arg)
32
+ end
33
+ end
34
+
35
+ def initialize(opts=defaults)
36
+ %i(origin destination
37
+ departure_date ip).each { |key| raise ArgumentError, "Must specify :#{key}" unless opts.keys.include? key }
38
+ options = defaults.merge(opts).select { |k,v| ALL_METHODS.include? k }
39
+ options.each { |k, v| self.send("#{k}=", v) }
40
+ end
41
+
42
+ def cabin=(symbol)
43
+ raise ArgumentError, "Cabin must be one of #{CABINS.keys}" unless CABINS.keys.include? symbol
44
+ @cabin = symbol
45
+ end
46
+
47
+ def ip=(arg)
48
+ @ip = IPAddr.new("#{arg}")
49
+ end
50
+
51
+ def roundtrip?
52
+ departure_date.present? && return_date.present?
53
+ end
54
+
55
+ def to_xml
56
+ <<-XML.strip_heredoc
57
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
58
+ #{header}
59
+ #{body}
60
+ </soap:Envelope>
61
+ XML
62
+ end
63
+
64
+ private
65
+
66
+ def defaults
67
+ {
68
+ adults: 1,
69
+ children: 1,
70
+ infants: 0,
71
+ cabin: :coach
72
+ }
73
+ end
74
+
75
+ def header
76
+ <<-HEADER.strip_heredoc
77
+ <soap:Header>
78
+ <AuthHeader xmlns="ezgds">
79
+ <Uname>#{client.username}</Uname>
80
+ <Pwd>#{client.password}</Pwd>
81
+ <URL>#{client.url_id}</URL>
82
+ <VisitSessionID>0</VisitSessionID>
83
+ <IP>#{ip}</IP>
84
+ </AuthHeader>
85
+ </soap:Header>
86
+ HEADER
87
+ end
88
+
89
+ def body
90
+ <<-BODY.strip_heredoc
91
+ <soap:Body>
92
+ <AFS1 xmlns="ezgds">
93
+ <ezQuoteAirRequest>
94
+ <QuoteAirRequestTrips>
95
+ #{depart_trip_xml}
96
+ #{return_trip_xml if roundtrip?}
97
+ </QuoteAirRequestTrips>
98
+ <PreferredAirline />
99
+ <Cabin>#{CABINS[cabin]}</Cabin>
100
+ <Adt>#{adults}</Adt>
101
+ <Chd>#{children}</Chd>
102
+ <Inf>#{infants}</Inf>
103
+ <PromoID>0</PromoID>
104
+ <CMPCode>0</CMPCode>
105
+ </ezQuoteAirRequest>
106
+ </AFS1>
107
+ </soap:Body>
108
+ BODY
109
+ end
110
+
111
+ def depart_trip_xml
112
+ <<-DEPART.strip_heredoc
113
+ <QuoteAirRequestTrip>
114
+ <DepDt>#{departure_date.strftime '%m/%d/%Y'}</DepDt>
115
+ <Orig>#{origin}</Orig>
116
+ <Dest>#{destination}</Dest>
117
+ </QuoteAirRequestTrip>
118
+ DEPART
119
+ end
120
+
121
+ def return_trip_xml
122
+ <<-RETURN.strip_heredoc
123
+ <QuoteAirRequestTrip>
124
+ <DepDt>#{return_date.strftime '%m/%d/%Y'}</DepDt>
125
+ <Orig>#{destination}</Orig>
126
+ <Dest>#{origin}</Dest>
127
+ </QuoteAirRequestTrip>
128
+ RETURN
129
+ end
130
+ end
@@ -0,0 +1,33 @@
1
+ # Returned by LBF::Client.search. This object contains an array of LBF::Quotes and an array of
2
+ # LBF::SearchErrors. :quotes will have a single element if a one-way flight was requeted, and two
3
+ # if a roundtrip flight was requested.
4
+ class LBF::Response
5
+ attr_reader :quotes, :errors
6
+ def initialize(hsh)
7
+ @hash = hsh
8
+ @errors = errors_from(@hash.deep_fetch :afs1_response, :afs1_result, :quote_air, :error_list)
9
+ @quotes = quotes_from(@hash.deep_fetch :afs1_response, :afs1_result, :quote_air)
10
+ end
11
+
12
+ def to_h
13
+ @hash
14
+ end
15
+
16
+ def error?
17
+ !errors.empty?
18
+ end
19
+
20
+ private
21
+
22
+ def errors_from(err_hash)
23
+ return [] if err_hash.nil?
24
+ err_hash.values.map { |msg| LBF::SearchError.new(msg) }
25
+ end
26
+
27
+ # Can be a hash or an array of hashes, so we have to handle that
28
+ def quotes_from(quotes_arr)
29
+ return [] if quotes_arr.nil?
30
+ quotes_arr = [quotes_arr].flatten
31
+ quotes_arr.map { |q| LBF::Quote.new(q) }
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ # A segment of an LBF trip. Since not everything from the incoming segment_hash is exposed, see comment
2
+ # below for segment information
3
+ class LBF::Segment
4
+ attr_reader :plane, :origin, :destination, :airline, :comments, :arrival, :departure, :flight
5
+ def initialize(segment_hash)
6
+ # {
7
+ # :equipment=>"Canadair Regional Jet 900", :e_ticket=>true, :equipment_code=>"CR9", :flight_stops=>"0",
8
+ # :airline=>"US", :orig=>"DFW", :duration=>nil, :dest=>"SDF", :airline_name=>"Us Airways",
9
+ # :flight_operator=>nil, :codeshare_comments=>"MESA AIRLINES AS AMERICAN EAGLE",
10
+ # :flight_operator_name=>"MESA AIRLINES AS AMERICAN EAGLE", :flight_number=>"5746",
11
+ # :orig_name=>"Dallas, Fort Worth Intl", :dest_name=>"Louisville, Louisville Intl",
12
+ # :arr_dt=>"04/04/2015", :dep_dt=>"04/04/2015", :arr_tm=>"1819", :dep_tm=>"1510", :arr_terminal=>nil,
13
+ # :dep_terminal=>"B", :connection_duration=>"0",
14
+ # :seats=>"7", :class_of_service=>"V", :cabin=>"Y",
15
+ # :cabin_name=>"Economy",
16
+ # :comments=> {
17
+ # :string=>"Operated By MESA AIRLINES AS AMERICAN EAGLE"
18
+ # },
19
+ # :segment_stops=> {
20
+ # :quote_air_segment_stop=> {
21
+ # :airport=>"DEN",
22
+ # :arrive_date=>"4/8/2015",
23
+ # :arrive_time=>"1531",
24
+ # :depart_date=>"4/8/2015",
25
+ # :depart_time=>"1621"
26
+ # }
27
+ # }
28
+ # }
29
+ @plane = LBF::Plane.new(segment_hash[:equipment], segment_hash[:equipment_code])
30
+ @e_ticket = segment_hash[:e_ticket]
31
+ @stops = segment_hash[:flight_stops].to_i
32
+ @origin = segment_hash[:orig]
33
+ @destination = segment_hash[:dest]
34
+ @airline = segment_hash[:airline_name]
35
+ @comments = comments_from segment_hash[:comments]
36
+ @arrival = DateTime.strptime("#{segment_hash[:arr_dt]} #{segment_hash[:arr_tm]}", '%m/%d/%Y %H%M')
37
+ @departure = DateTime.strptime("#{segment_hash[:dep_dt]} #{segment_hash[:dep_tm]}", '%m/%d/%Y %H%M')
38
+ @flight = segment_hash[:flight_number].to_i
39
+ end
40
+
41
+ def e_ticket?
42
+ @e_ticket
43
+ end
44
+
45
+ private
46
+
47
+ def comments_from(comments_hash)
48
+ return [] if comments_hash.nil?
49
+ comments_hash.values
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ # A traveler, according to LBF
2
+ class LBF::Traveler
3
+ TRAVELER_CATEGORY = LBF::Request::CABINS.invert
4
+ def initialize(trav_hash)
5
+ @category = TRAVELER_CATEGORY[trav_hash[:category].upcase]
6
+ @fare = BigDecimal.new trav_hash[:fare]
7
+ @taxes_and_fees = BigDecimal.new trav_hash[:fare_tax_and_fees]
8
+ @total_price = BigDecimal.new trav_hash[:fare_total]
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ # A trip, e.g. from LAS to LAX. Will contain multiple segments if it isn't a non-stop flight. Also
2
+ # includes layover information. Segments can have segment stops, for stops that aren't segments. This might
3
+ # mean that the plane stops, but the traveler doesn't get off. It's not clear from the documentation.
4
+ # Segment stops are not exposed.
5
+ class LBF::Trip
6
+ attr_reader :duration, :arrival, :departure, :origin, :destination, :notes
7
+
8
+ # NB: The :duration method (and corresponding ivar) are in seconds
9
+ def initialize(trip_hash)
10
+ @duration = trip_hash[:duration].to_i.minutes
11
+ @arrival = DateTime.strptime("#{trip_hash[:arr_dt]} #{trip_hash[:arr_tm]}", '%m/%d/%Y %H%M')
12
+ @departure = DateTime.strptime("#{trip_hash[:dep_dt]} #{trip_hash[:dep_tm]}", '%m/%d/%Y %H%M')
13
+ @origin = trip_hash[:orig]
14
+ @destination = trip_hash[:dest]
15
+ @notes = trip_hash[:duration_notes]
16
+ @segments = segments_from(trip_hash.deep_fetch :quote_air_segments, :quote_air_segment)
17
+ @layovers = layovers_from(trip_hash.deep_fetch :quote_air_segments, :quote_air_segment)
18
+ end
19
+
20
+ private
21
+
22
+ def layovers_from(segment_arr)
23
+ return [] if segment_arr.nil?
24
+ segment_arr.map { |s| LBF::Layover.new(s) unless s[:connection_duration].to_i == 0 }.compact
25
+ end
26
+
27
+ def segments_from(segment_arr)
28
+ return [] if segment_arr.nil?
29
+ segment_arr.map { |s| LBF::Segment.new s }
30
+ end
31
+
32
+ end
@@ -0,0 +1,3 @@
1
+ module LBF
2
+ VERSION = "0.0.1"
3
+ end
data/lib/lbf.rb ADDED
@@ -0,0 +1,22 @@
1
+ module LBF
2
+ end
3
+ require 'lbf/version'
4
+ require 'lbf/lbf_client'
5
+ require 'lbf/lbf_request'
6
+ require 'lbf/lbf_response'
7
+ require 'lbf/lbf_exceptions'
8
+ require 'lbf/lbf_quote'
9
+ require 'lbf/lbf_trip'
10
+ require 'lbf/lbf_traveler'
11
+ require 'lbf/lbf_fare'
12
+ require 'lbf/lbf_segment'
13
+ require 'lbf/lbf_plane'
14
+ require 'lbf/lbf_layover'
15
+ require 'lbf/deep_fetch'
16
+ require 'savon'
17
+ require 'pp'
18
+ require 'date'
19
+ require 'active_support/all'
20
+ require 'ipaddr'
21
+ require 'bigdecimal'
22
+ I18n.config.enforce_available_locales = false
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: LBF
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Forrest Fleming
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: savon
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.10'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubyntlm
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.3.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.1'
69
+ description: Pile of service objects for making requests to the LBF API and its responses
70
+ email:
71
+ - ffleming@oversee.net
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - lbf.gemspec
82
+ - lib/lbf.rb
83
+ - lib/lbf/deep_fetch.rb
84
+ - lib/lbf/lbf_client.rb
85
+ - lib/lbf/lbf_exceptions.rb
86
+ - lib/lbf/lbf_fare.rb
87
+ - lib/lbf/lbf_layover.rb
88
+ - lib/lbf/lbf_plane.rb
89
+ - lib/lbf/lbf_quote.rb
90
+ - lib/lbf/lbf_request.rb
91
+ - lib/lbf/lbf_response.rb
92
+ - lib/lbf/lbf_segment.rb
93
+ - lib/lbf/lbf_traveler.rb
94
+ - lib/lbf/lbf_trip.rb
95
+ - lib/lbf/version.rb
96
+ homepage: https://github.com/Oversee/Travel-LBFSoap
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.2.2
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Gem for making requests from LBF API
120
+ test_files: []