Class: Fop::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/fop/client.rb

Instance Method Summary collapse

Constructor Details

#initializeClient

Returns a new instance of Client.



38
39
# File 'lib/fop/client.rb', line 38

def initialize()
end

Instance Method Details

#data_jsObject



204
205
206
# File 'lib/fop/client.rb', line 204

def data_js
  @data_js ||= open(DATA_JS_URI, 'r', &:read)
end

#dom_search(from:, to:, class:, fare:, card: '-', status: '-') ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/fop/client.rb', line 41

def dom_search(from:, to:, class:, fare:, card: '-', status: '-')
  klass = binding.local_variable_get(:class)

  unless valid_dom_airports.any?{ |_| _.code == from.to_s }
    raise InvalidAirport, "#{from.inspect} is invalid airport"
  end
  unless valid_dom_airports.any?{ |_| _.code == to.to_s }
    raise InvalidAirport, "#{to.inspect} is invalid airport"
  end

  page = post_form(
    cmd: 'do_search',
    TYPE: 'D',
    external: '',
    CityFrom: from.to_s,
    CityTo: to.to_s,
    F_CLASS: klass.to_s,
    F_JAL_CARD: card.to_s,
    F_JAL_CARD_STATUS: status.to_s,
    F_FARE: fare.to_s,
  )
  parse_result(page.at('#contentDom'))
end

#form_pageObject



200
201
202
# File 'lib/fop/client.rb', line 200

def form_page
  @form_page ||= Nokogiri::HTML(open(ENDPOINT_URI, 'r', &:read))
end

#intl_search(from:, to:, fare:, card: '-', status: '-') ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/fop/client.rb', line 65

def intl_search(from:, to:, fare:, card: '-', status: '-')
  from_airport = valid_intl_airports_for_earning.find{ |_| _.code == from.to_s }
  to_airport = valid_intl_airports_for_earning.find{ |_| _.code == to.to_s }
  unless from_airport
    raise InvalidAirport, "#{from.inspect} is invalid airport"
  end
  unless to_airport
    raise InvalidAirport, "#{to.inspect} is invalid airport"
  end

  page = post_form(
    cmd: 'do_search',
    TYPE: 'I',
    external: '',
    AreaFrom: from_airport.area,
    AreaTo: to_airport.area,
    CityFrom: from_airport.code,
    CityTo: to_airport.code,
    F_JAL_CARD: card.to_s,
    F_JAL_CARD_STATUS: status.to_s,
    F_FARE: fare.to_s,
  )
  parse_result(page.at('#contentInt'))
end

#parse_data_js(variable) ⇒ Object



185
186
187
188
189
190
191
192
193
194
# File 'lib/fop/client.rb', line 185

def parse_data_js(variable)
  m = data_js.match(/^var #{Regexp.escape(variable)} = (.+?\r?\n[\]}]);$/m)
  raise DataParseError, "Failed to extract #{variable.inspect} from data_js" unless m
  js = m[1]
  json_like = js.
    gsub(/^\s*"(.+?)"\s*:|^\s*(.+?)\s*:/,'"\1\2":')
  JSON.parse json_like
rescue JSON::ParserError
  raise DataParseError, "Failed to parse #{variable.inspect} from data_js"
end

#parse_result(page) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/fop/client.rb', line 90

def parse_result(page)
  if page.inner_text.include?("ご入力いただいた条件では検索できませんでした")
    raise ConditionError, "Calculation not available for given query"
  end

  miles, fop = page.search('.milecount').map{ |_| _.inner_text.strip.gsub(/,/, '').to_i }
  standard_flight_miles = page.search('.milecount')[0].parent.children[1].inner_text.gsub(/[^\d]+/,'').to_i

  miles_breakdown, fop_breakdown = page.search('.Flightmilebns').map do |elem|
    elem.search('.FlightmilebnsItem').reject{ |_| _['class'].include?('Mark') }
  end

  flight_miles_elem = miles_breakdown[0]
  flight_miles = flight_miles_elem.at('.FlightmilebnsNum').inner_text.strip.gsub(/,/, '').to_i
  flight_miles_remark = flight_miles_elem.at('.FlightmilebnsTitle').inner_text.gsub(/\s+|\r?\n/, ' ')

  bonus_miles_elem = miles_breakdown[1]
  if bonus_miles_elem
    bonus_miles = bonus_miles_elem.at('.FlightmilebnsNum').inner_text.strip.gsub(/,/, '').to_i
    bonus_miles_remark = bonus_miles_elem.at('.FlightmilebnsTitle').inner_text.gsub(/\s+|\r?\n/, ' ')
  end

  fop_rate_elem = fop_breakdown[1]
  fop_rate = fop_rate_elem.at('.FlightmilebnsNum').inner_text.strip.gsub(/,/, '').to_f

  fop_bonus_elem = fop_breakdown[2]
  if fop_bonus_elem
    fop_bonus = fop_bonus_elem.at('.FlightmilebnsNum').inner_text.strip.gsub(/,/, '').to_i
    fop_bonus_remark = fop_bonus_elem.at('.FlightmilebnsTitle').inner_text.gsub(/\s+|\r?\n/, ' ')
  end

  Result.new(miles, fop, flight_miles, flight_miles_remark, standard_flight_miles, bonus_miles, bonus_miles_remark, fop_rate, fop_bonus, fop_bonus_remark)
end

#post_form(data) ⇒ Object



196
197
198
# File 'lib/fop/client.rb', line 196

def post_form(data)
  Nokogiri::HTML(Net::HTTP.post_form(ENDPOINT_URI, data).tap(&:value).body)
end

#valid_cardsObject



124
125
126
127
128
# File 'lib/fop/client.rb', line 124

def valid_cards
  @valid_card_types ||= form_page.search('#intCardtype option').map do |option|
    CardType.new(option['value'], option.inner_text.strip)
  end
end

#valid_dom_airportsObject



144
145
146
147
148
# File 'lib/fop/client.rb', line 144

def valid_dom_airports
  @valid_dom_airports ||= parse_data_js("dom_city").map do |(name, code)|
    Airport.new(code, nil, name)
  end
end

#valid_dom_classesObject



150
151
152
153
154
# File 'lib/fop/client.rb', line 150

def valid_dom_classes
  @valid_dom_classes ||= form_page.search('#domClass option').map do |option|
    SeatClass.new(option['value'], option.inner_text.strip)
  end
end

#valid_dom_faresObject



156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/fop/client.rb', line 156

def valid_dom_fares
  @valid_dom_fares ||= begin
     feelist = form_page.search('.feelist')[0].search('tr').map do |tr|
       tr.search('td').map(&:inner_text).map(&:strip)
     end.reject(&:empty?).to_h

     form_page.search('#domFare option').map do |option|
       name = option.inner_text.strip
       remark = feelist[name]
       Fare.new(option['value'], name, remark)
     end
   end
end

#valid_intl_airports_for_earningObject



136
137
138
139
140
141
142
# File 'lib/fop/client.rb', line 136

def valid_intl_airports_for_earning
  @valid_airports_for_earning ||= parse_data_js("save_city_hash").flat_map do |area, airports|
    airports.map do |(name, code)|
      Airport.new(code, area, name)
    end
  end
end

#valid_intl_faresObject



170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/fop/client.rb', line 170

def valid_intl_fares
  @valid_intl_fares ||= begin
     feelist = form_page.search('.feelist')[1].search('tr').map do |tr|
       tr.search('td').map(&:inner_text).map(&:strip)
     end.reject(&:empty?).to_h

     form_page.search('#intFare option').map do |option|
       name = option.inner_text.strip
       remark = feelist[name]
       Fare.new(option['value'], name, remark)
     end
   end
end

#valid_statusesObject



130
131
132
133
134
# File 'lib/fop/client.rb', line 130

def valid_statuses
  @valid_statuses ||= parse_data_js("status_hash").fetch('g_club').map do |(name, code)|
    Status.new(code.to_s, name)
  end
end