module JourneyFuel
Constants
- DEFAULT_CONSUMPTION_L_PER_100KM
- DIESEL_FUEL_TYPES
- FUEL_API_URL
-
Fueldata source (11-Seven / projectzerothree regional best prices). The fetch lambda is injected in tests so no live HTTP is required. - PETROL_FUEL_TYPES
- STATE_NAMES
- STATE_PATTERN
- SUPPORTED_FUEL_REGIONS
Public Instance Methods
Source
# File plugins/distance.rb, line 230 def append_fuel_to_report(report, data:, fetch:, consumption: DEFAULT_CONSUMPTION_L_PER_100KM, fuel_type: nil) card = fuel_card_for_directions_data( data, fetch: fetch, consumption: consumption, fuel_type: fuel_type ) card ? "#{report}\n#{card}" : report end
Source
# File plugins/distance.rb, line 175 def average_vehicle_line(prices:, distance_km:, consumption:, fuel_type: nil) return nil unless prices && distance_km case fuel_type when :diesel return nil if prices[:diesel].nil? cost = journey_fuel_cost( distance_km: distance_km, price_per_litre: prices[:diesel], consumption: consumption ) "Average vehicle 路 trip #{format_currency(cost)} 路 #{format_price_per_litre(prices[:diesel])} 路 #{consumption} L/100km" when :petrol return nil if prices[:petrol].nil? cost = journey_fuel_cost( distance_km: distance_km, price_per_litre: prices[:petrol], consumption: consumption ) "Average vehicle 路 trip #{format_currency(cost)} 路 #{format_price_per_litre(prices[:petrol])} 路 #{consumption} L/100km" else costs = [prices[:petrol], prices[:diesel]].compact.map do |ppl| journey_fuel_cost(distance_km: distance_km, price_per_litre: ppl, consumption: consumption) end return nil if costs.empty? average = (costs.sum / costs.size).round(2) "Average vehicle 路 trip #{format_currency(average)} 路 #{consumption} L/100km" end end
Source
# File plugins/distance.rb, line 135 def build_fuel_url(_region = nil) FUEL_API_URL end
Source
# File plugins/distance.rb, line 156 def format_currency(amount) return nil if amount.nil? format("$%.2f", amount) end
Source
# File plugins/distance.rb, line 204 def format_fuel_card(prices:, distance_km:, region: nil, consumption: DEFAULT_CONSUMPTION_L_PER_100KM, fuel_type: nil) return nil unless prices && distance_km title = region.to_s.strip.empty? ? "Fuel" : "Fuel 路 #{region}" lines = [IrcFormat.report_header(tag: "Fuel", title: title)] lines << fuel_line("Petrol", prices[:petrol], distance_km: distance_km, consumption: consumption) lines << fuel_line("Diesel", prices[:diesel], distance_km: distance_km, consumption: consumption) lines << average_vehicle_line( prices: prices, distance_km: distance_km, consumption: consumption, fuel_type: fuel_type ) lines << IrcFormat.report_footer("fuel prices", region, "avg #{consumption} L/100km") lines.compact.join("\n") end
Source
# File plugins/distance.rb, line 162 def format_price_per_litre(dollars) return nil if dollars.nil? format("%.1fc/L", dollars * 100) end
Source
# File plugins/distance.rb, line 221 def fuel_card_for_directions_data(data, fetch:, consumption: DEFAULT_CONSUMPTION_L_PER_100KM, fuel_type: nil) distance_km = total_distance_km(data) region = region_from_data(data) prices = fuel_prices(region, fetch: fetch) format_fuel_card( prices: prices, distance_km: distance_km, region: region, consumption: consumption, fuel_type: fuel_type ) end
Source
# File plugins/distance.rb, line 168 def fuel_line(label, price_per_litre, distance_km:, consumption:) return nil if price_per_litre.nil? cost = journey_fuel_cost(distance_km: distance_km, price_per_litre: price_per_litre, consumption: consumption) "#{label} 路 #{format_price_per_litre(price_per_litre)} 路 trip #{format_currency(cost)}" end
Source
# File plugins/distance.rb, line 139 def fuel_prices(region, fetch:) region = region.to_s.strip.upcase return nil if region.empty? || !SUPPORTED_FUEL_REGIONS.include?(region) url = build_fuel_url(region) parse_fuel_prices(fetch.call(url), region: region) rescue StandardError nil end
Source
# File plugins/distance.rb, line 149 def journey_fuel_cost(distance_km:, price_per_litre:, consumption: DEFAULT_CONSUMPTION_L_PER_100KM) return nil if distance_km.nil? || price_per_litre.nil? litres = distance_km.to_f / 100.0 * consumption.to_f (litres * price_per_litre.to_f).round(2) end
Source
# File plugins/distance.rb, line 237 def maps_report(route_text, fetch:, api_key:, fuel_fetch:, consumption: DEFAULT_CONSUMPTION_L_PER_100KM) result = Maps.fetch_directions(route_text, fetch: fetch, api_key: api_key) return result if result.is_a?(String) directions = Maps.format_directions(result[:data], route: result[:route]) append_fuel_to_report(directions, data: result[:data], fetch: fuel_fetch, consumption: consumption) rescue StandardError "Could not fetch directions" end
Source
# File plugins/distance.rb, line 94 def parse_fuel_entries(entries) petrol = nil diesel = nil entries.each do |entry| fuel = (entry["fuel"] || entry[:fuel] || entry["type"] || entry[:type]).to_s price = entry["price"] || entry[:price] next if price.nil? dollars = price.to_f / 100.0 if fuel.match?(DIESEL_FUEL_TYPES) diesel ||= dollars elsif fuel.match?(PETROL_FUEL_TYPES) petrol ||= dollars end end return nil if petrol.nil? && diesel.nil? { petrol: petrol, diesel: diesel } end
Source
# File plugins/distance.rb, line 117 def parse_fuel_prices(data, region: nil) data = JSON.parse(data) if data.is_a?(String) if data["regions"] region_code = region.to_s.strip.upcase return nil if region_code.empty? region_data = data["regions"].find { |entry| entry["region"].to_s.upcase == region_code } return nil unless region_data return parse_fuel_entries(region_data["prices"] || []) end parse_fuel_entries(data["prices"] || data[:prices] || []) rescue JSON::ParserError nil end
Fuel prices are reported in cents per litre; return dollars per litre.
Source
# File plugins/distance.rb, line 71 def region_from_data(data) data = JSON.parse(data) if data.is_a?(String) routes = data["routes"] return nil if routes.nil? || routes.empty? legs = routes.first["legs"] || [] addresses = [] addresses << legs.last&.dig("end_address") legs.each do |leg| addresses << leg["start_address"] addresses << leg["end_address"] end addresses.compact.each do |address| state = state_from_address(address) return state if state end nil rescue JSON::ParserError nil end
Source
# File plugins/distance.rb, line 56 def state_from_address(address) text = address.to_s return nil if text.strip.empty? if (match = text.match(STATE_PATTERN)) return match[1].upcase end STATE_NAMES.each do |name, abbrev| return abbrev if text.match?(/\b#{Regexp.escape(name)}\b/i) end nil end
Source
# File plugins/distance.rb, line 40 def total_distance_km(data) data = JSON.parse(data) if data.is_a?(String) routes = data["routes"] return nil if routes.nil? || routes.empty? legs = routes.first["legs"] || [] return nil if legs.empty? meters = legs.sum { |leg| leg.dig("distance", "value").to_i } return nil if meters.zero? (meters / 1000.0).round(2) rescue JSON::ParserError nil end