earth 0.5.2 → 0.5.3

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.
Files changed (88) hide show
  1. data/Gemfile +1 -1
  2. data/LICENSE-PREAMBLE +1 -1
  3. data/Rakefile +3 -0
  4. data/earth.gemspec +1 -1
  5. data/lib/earth.rb +7 -7
  6. data/lib/earth/air/aircraft.rb +15 -0
  7. data/lib/earth/air/aircraft/data_miner.rb +65 -77
  8. data/lib/earth/air/aircraft_class.rb +1 -1
  9. data/lib/earth/air/aircraft_fuel_use_equation.rb +1 -1
  10. data/lib/earth/air/airline.rb +1 -1
  11. data/lib/earth/air/airport.rb +1 -1
  12. data/lib/earth/air/bts_aircraft.rb +1 -1
  13. data/lib/earth/air/flight_distance_class.rb +1 -1
  14. data/lib/earth/air/flight_seat_class.rb +1 -1
  15. data/lib/earth/air/flight_segment.rb +1 -1
  16. data/lib/earth/air/flight_segment/data_miner.rb +24 -46
  17. data/lib/earth/automobile/automobile_fuel.rb +1 -1
  18. data/lib/earth/automobile/automobile_make.rb +1 -1
  19. data/lib/earth/automobile/automobile_make_fleet_year.rb +1 -1
  20. data/lib/earth/automobile/automobile_make_model.rb +1 -1
  21. data/lib/earth/automobile/automobile_make_model_year.rb +1 -1
  22. data/lib/earth/automobile/automobile_make_model_year_variant.rb +1 -1
  23. data/lib/earth/automobile/automobile_make_year.rb +1 -1
  24. data/lib/earth/automobile/automobile_size_class.rb +1 -1
  25. data/lib/earth/automobile/automobile_size_class_year.rb +1 -1
  26. data/lib/earth/automobile/automobile_type_fuel_age.rb +1 -1
  27. data/lib/earth/automobile/automobile_type_fuel_control.rb +1 -1
  28. data/lib/earth/automobile/automobile_type_fuel_year.rb +1 -1
  29. data/lib/earth/automobile/automobile_type_fuel_year_age.rb +1 -1
  30. data/lib/earth/automobile/automobile_type_fuel_year_control.rb +1 -1
  31. data/lib/earth/automobile/automobile_type_year.rb +1 -1
  32. data/lib/earth/bus/bus_class.rb +1 -1
  33. data/lib/earth/bus/bus_fuel.rb +1 -1
  34. data/lib/earth/bus/bus_fuel_control.rb +1 -1
  35. data/lib/earth/bus/bus_fuel_year_control.rb +1 -1
  36. data/lib/earth/computation/computation_carrier.rb +1 -1
  37. data/lib/earth/computation/computation_carrier_instance_class.rb +1 -1
  38. data/lib/earth/computation/computation_carrier_region.rb +1 -1
  39. data/lib/earth/conversions_ext.rb +1 -0
  40. data/lib/earth/diet/diet_class.rb +1 -1
  41. data/lib/earth/diet/food_group.rb +1 -1
  42. data/lib/earth/fuel/fuel.rb +1 -1
  43. data/lib/earth/fuel/fuel_price.rb +1 -1
  44. data/lib/earth/fuel/fuel_type.rb +1 -1
  45. data/lib/earth/fuel/fuel_year.rb +1 -1
  46. data/lib/earth/fuel/greenhouse_gas.rb +1 -1
  47. data/lib/earth/hospitality/lodging_class.rb +1 -1
  48. data/lib/earth/industry/industry.rb +1 -1
  49. data/lib/earth/industry/industry_product.rb +1 -1
  50. data/lib/earth/industry/industry_product_line.rb +1 -1
  51. data/lib/earth/industry/industry_sector.rb +1 -1
  52. data/lib/earth/industry/merchant.rb +1 -1
  53. data/lib/earth/industry/merchant_category.rb +1 -1
  54. data/lib/earth/industry/merchant_category_industry.rb +1 -1
  55. data/lib/earth/industry/product_line.rb +1 -1
  56. data/lib/earth/industry/product_line_industry_product.rb +1 -1
  57. data/lib/earth/industry/sector.rb +1 -1
  58. data/lib/earth/locality/census_division.rb +1 -1
  59. data/lib/earth/locality/census_region.rb +1 -1
  60. data/lib/earth/locality/climate_division.rb +1 -1
  61. data/lib/earth/locality/country.rb +1 -1
  62. data/lib/earth/locality/egrid_region.rb +1 -1
  63. data/lib/earth/locality/egrid_region/data_miner.rb +10 -0
  64. data/lib/earth/locality/egrid_subregion.rb +1 -1
  65. data/lib/earth/locality/petroleum_administration_for_defense_district.rb +1 -1
  66. data/lib/earth/locality/state.rb +1 -1
  67. data/lib/earth/locality/urbanity.rb +1 -1
  68. data/lib/earth/locality/zip_code.rb +1 -1
  69. data/lib/earth/pet/breed.rb +1 -1
  70. data/lib/earth/pet/breed_gender.rb +1 -1
  71. data/lib/earth/pet/gender.rb +1 -1
  72. data/lib/earth/pet/species.rb +1 -1
  73. data/lib/earth/rail/rail_class.rb +1 -1
  74. data/lib/earth/residence/air_conditioner_use.rb +1 -1
  75. data/lib/earth/residence/clothes_machine_use.rb +1 -1
  76. data/lib/earth/residence/dishwasher_use.rb +1 -1
  77. data/lib/earth/residence/residence_appliance.rb +1 -1
  78. data/lib/earth/residence/residence_class.rb +1 -1
  79. data/lib/earth/residence/residence_fuel_price.rb +1 -1
  80. data/lib/earth/residence/residence_fuel_type.rb +1 -1
  81. data/lib/earth/residence/residential_energy_consumption_survey_response.rb +1 -1
  82. data/lib/earth/residence/residential_energy_consumption_survey_response/data_miner.rb +9 -9
  83. data/lib/earth/shipping/carrier.rb +1 -1
  84. data/lib/earth/shipping/carrier_mode.rb +1 -1
  85. data/lib/earth/shipping/shipment_mode.rb +1 -1
  86. data/lib/earth/version.rb +1 -1
  87. data/spec/earth/air/aircraft_spec.rb +1 -1
  88. metadata +42 -44
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  gem 'data_miner', :path => ENV['LOCAL_DATA_MINER'] if ENV['LOCAL_DATA_MINER']
2
- gem 'create_table', :path => ENV['LOCAL_CREATE_TABLE'] if ENV['LOCAL_CREATE_TABLE']
2
+ gem 'force_schema', :path => ENV['LOCAL_FORCE_SCHEMA'] if ENV['LOCAL_FORCE_SCHEMA']
3
3
 
4
4
  source :rubygems
5
5
 
@@ -9,7 +9,7 @@ IDENTITY OF THE SOFTWARE MODULE COVERED BY LICENSE:
9
9
 
10
10
  This license covers the Brighter Planet reference data import module,
11
11
  referred to as 'earth,' officially distributed from
12
- http://github.com/brighterplanet/earth.
12
+ https://github.com/brighterplanet/earth.
13
13
 
14
14
  SCOPE OF THE SOFTWARE MODULE COVERED BY LICENSE:
15
15
 
data/Rakefile CHANGED
@@ -24,6 +24,9 @@ Cucumber::Rake::Task.new(:features) do |t|
24
24
  end
25
25
  end
26
26
 
27
+ directory 'log/'
28
+ task :features => 'log/'
29
+
27
30
  if RUBY_VERSION =~ /^1\.8/
28
31
  desc "Run cucumber tests with RCov"
29
32
  Cucumber::Rake::Task.new(:features_with_coverage) do |t|
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.add_runtime_dependency 'geokit-rails'
37
37
  s.add_runtime_dependency 'loose_tight_dictionary', '>=0.2.3'
38
38
  s.add_runtime_dependency 'weighted_average'
39
- s.add_runtime_dependency 'create_table', '>=0.0.2'
39
+ s.add_runtime_dependency 'force_schema', '>=0.0.2'
40
40
  s.add_development_dependency 'bundler'
41
41
  s.add_development_dependency 'bueller'
42
42
  s.add_development_dependency 'cucumber'
@@ -7,7 +7,7 @@ require 'falls_back_on'
7
7
  require 'weighted_average'
8
8
  require 'fixed_width'
9
9
  require 'errata'
10
- require 'create_table'
10
+ require 'force_schema'
11
11
  require 'loose_tight_dictionary'
12
12
  require 'loose_tight_dictionary/cached_result'
13
13
 
@@ -119,13 +119,13 @@ module Earth
119
119
  resource_model.data_miner_config.steps.push pull_dependencies_step
120
120
  end
121
121
 
122
- def _prepend_create_table_step_to_data_miner(resource)
122
+ def _prepend_force_schema_step_to_data_miner(resource)
123
123
  resource_model = resource.constantize
124
- return if resource_model.data_miner_config.steps.any? { |step| step.description == :create_table! }
124
+ return if resource_model.data_miner_config.steps.any? { |step| step.description == :force_schema! }
125
125
 
126
- create_table_step = DataMiner::Process.new resource_model.data_miner_config, :create_table!
126
+ force_schema_step = DataMiner::Process.new resource_model.data_miner_config, :force_schema!
127
127
 
128
- resource_model.data_miner_config.steps.unshift create_table_step
128
+ resource_model.data_miner_config.steps.unshift force_schema_step
129
129
  end
130
130
 
131
131
  TAPS_STEP = 'Tap the Brighter Planet data server'
@@ -144,7 +144,7 @@ module Earth
144
144
  next unless ::Object.const_defined?(resource)
145
145
  _append_pull_dependencies_step_to_data_miner resource
146
146
  if options[:apply_schemas] or options[:load_data_miner]
147
- _prepend_create_table_step_to_data_miner resource
147
+ _prepend_force_schema_step_to_data_miner resource
148
148
  else
149
149
  _prepend_taps_step_to_data_miner resource
150
150
  end
@@ -154,7 +154,7 @@ module Earth
154
154
  def _load_schemas(selected_resources, options)
155
155
  return unless options[:apply_schemas]
156
156
  selected_resources.each do |resource|
157
- resource.constantize.create_table!
157
+ resource.constantize.force_schema!
158
158
  end
159
159
  end
160
160
  end
@@ -17,6 +17,21 @@ class Aircraft < ActiveRecord::Base
17
17
  end
18
18
  end
19
19
 
20
+ force_schema do
21
+ string 'icao_code'
22
+ string 'manufacturer_name'
23
+ string 'model_name'
24
+ string 'description'
25
+ string 'aircraft_type'
26
+ string 'engine_type'
27
+ integer 'engines'
28
+ string 'weight_class'
29
+ string 'class_code'
30
+ string 'fuel_use_code'
31
+ float 'seats'
32
+ float 'passengers'
33
+ end
34
+
20
35
  # Enable aircraft.flight_segments
21
36
  cache_loose_tight_dictionary_matches_with :flight_segments, :primary_key => :description, :foreign_key => :aircraft_description
22
37
  end
@@ -20,22 +20,69 @@ Aircraft.class_eval do
20
20
  @manufacturer_whitelist ||= RemoteTable.new(:url => 'https://spreadsheets.google.com/spreadsheet/pub?key=0AoQJbWqPrREqdFRFalpOdlg1cnF6amlSM1dDc1lya2c&output=csv').map { |record| record['Manufacturer'].to_regexp }
21
21
  @manufacturer_whitelist.any? { |manufacturer_regexp| manufacturer_regexp.match candidate }
22
22
  end
23
-
24
- create_table do
25
- string 'icao_code'
26
- string 'manufacturer_name'
27
- string 'model_name'
28
- string 'description'
29
- string 'aircraft_type'
30
- string 'engine_type'
31
- integer 'engines'
32
- string 'weight_class'
33
- string 'class_code'
34
- string 'fuel_use_code'
35
- float 'seats'
36
- float 'passengers'
23
+
24
+ # FIXME TODO do we want to restrict this to certain years?
25
+ # Derive some average characteristics from flight segments
26
+ def self.update_averages!
27
+ FlightSegment.run_data_miner!
28
+ manually_cache_flight_segments!
29
+ find_each do |aircraft|
30
+ aircraft.seats = aircraft.flight_segments.weighted_average :seats_per_flight, :weighted_by => :passengers
31
+ aircraft.passengers = aircraft.flight_segments.sum :passengers
32
+ aircraft.save
33
+ end
37
34
  end
38
35
 
36
+ # Cache fuzzy matches between FlightSegment aircraft_description and Aircraft description
37
+ def self.manually_cache_flight_segments!
38
+ FlightSegment.run_data_miner!
39
+ LooseTightDictionary::CachedResult.setup
40
+ FlightSegment.find_by_sql("SELECT * FROM flight_segments GROUP BY aircraft_description HAVING aircraft_description IS NOT NULL").each do |flight_segment|
41
+ original_description = flight_segment.aircraft_description
42
+
43
+ # If the flight segment's aircraft_description contains '/' then it describes multiple aircraft.
44
+ # We need to synthesize descriptions for those aircraft, find all Aircraft that fuzzily match the
45
+ # synthesized descriptions, and associate those Aircraft with the original aircraft_description.
46
+ # e.g. boeing 747-100/200
47
+ if original_description.include?("/")
48
+ # Pull out the complete first aircraft description
49
+ # e.g. 'boeing 747-100'
50
+ first_description = original_description.split('/')[0]
51
+
52
+ # Pull out the root of the description - the text up to and including the last ' ' or '-'
53
+ # e.g. 'boeing 747-'
54
+ root_length = first_description.rindex(/[ \-]/)
55
+ root = first_description.slice(0..root_length)
56
+
57
+ # Pull out the suffixes - the text separated by forward slashes
58
+ # e.g. ['100', '200']
59
+ suffixes = original_description.split(root)[1].split('/')
60
+
61
+ # Create an array of synthesized descriptions by appending each suffix to the root
62
+ # e.g. ['boeing 747-100', 'boeing 747-200']
63
+ suffixes.map{ |suffix| root + suffix }.each do |synthesized_description|
64
+ # Look up the Aircraft that match each synthesized description and associate
65
+ # them with the original flight segment aircraft_description
66
+ Aircraft.loose_tight_dictionary.find_all(synthesized_description).each do |aircraft|
67
+ attrs = {
68
+ :a_class => "Aircraft",
69
+ :a => aircraft.description,
70
+ :b_class => "FlightSegment",
71
+ :b => original_description
72
+ }
73
+ unless ::LooseTightDictionary::CachedResult.exists? attrs
74
+ ::LooseTightDictionary::CachedResult.create! attrs
75
+ end
76
+ end
77
+ end
78
+ # If the flight segment's aircraft_description doesn't contain '/' we can use
79
+ # a method provided by loose_tight_dictionary to associate it with Aircraft
80
+ else
81
+ flight_segment.cache_aircraft!
82
+ end
83
+ end
84
+ end
85
+
39
86
  data_miner do
40
87
  ('A'..'Z').each do |letter|
41
88
  import("aircraft made by whitelisted manufacturers whose ICAO code starts with '#{letter}' from the FAA",
@@ -73,13 +120,13 @@ Aircraft.class_eval do
73
120
  end
74
121
 
75
122
  process "Synthesize description from manufacturer name and model name" do
76
- Aircraft.find_each do |aircraft|
123
+ find_each do |aircraft|
77
124
  aircraft.update_attribute :description, [aircraft.manufacturer_name, aircraft.model_name].join(' ').downcase
78
125
  end
79
126
  end
80
127
 
81
128
  process "Synthesize class code from engine type and weight class" do
82
- Aircraft.find_each do |aircraft|
129
+ find_each do |aircraft|
83
130
  size = case aircraft.weight_class
84
131
  when 'Small', 'Small+', 'Light'
85
132
  'Light'
@@ -92,67 +139,8 @@ Aircraft.class_eval do
92
139
  end
93
140
  end
94
141
 
95
- process "Ensure FlightSegment is populated" do
96
- FlightSegment.run_data_miner!
97
- end
98
-
99
- process "Cache fuzzy matches between FlightSegment aircraft_description and Aircraft description" do
100
- LooseTightDictionary::CachedResult.setup
101
- FlightSegment.find_by_sql("SELECT * FROM flight_segments GROUP BY aircraft_description HAVING aircraft_description IS NOT NULL").each do |flight_segment|
102
- original_description = flight_segment.aircraft_description
103
-
104
- # If the flight segment's aircraft_description contains '/' then it describes multiple aircraft.
105
- # We need to synthesize descriptions for those aircraft, find all Aircraft that fuzzily match the
106
- # synthesized descriptions, and associate those Aircraft with the original aircraft_description.
107
- # e.g. boeing 747-100/200
108
- if original_description.include?("/")
109
- # Pull out the complete first aircraft description
110
- # e.g. 'boeing 747-100'
111
- first_description = original_description.split('/')[0]
112
-
113
- # Pull out the root of the description - the text up to and including the last ' ' or '-'
114
- # e.g. 'boeing 747-'
115
- root_length = first_description.rindex(/[ \-]/)
116
- root = first_description.slice(0..root_length)
117
-
118
- # Pull out the suffixes - the text separated by forward slashes
119
- # e.g. ['100', '200']
120
- suffixes = original_description.split(root)[1].split('/')
121
-
122
- # Create an array of synthesized descriptions by appending each suffix to the root
123
- # e.g. ['boeing 747-100', 'boeing 747-200']
124
- suffixes.map{ |suffix| root + suffix }.each do |synthesized_description|
125
- # Look up the Aircraft that match each synthesized description and associate
126
- # them with the original flight segment aircraft_description
127
- Aircraft.loose_tight_dictionary.find_all(synthesized_description).each do |aircraft|
128
- attrs = {
129
- :a_class => "Aircraft",
130
- :a => aircraft.description,
131
- :b_class => "FlightSegment",
132
- :b => original_description
133
- }
134
- unless ::LooseTightDictionary::CachedResult.exists? attrs
135
- ::LooseTightDictionary::CachedResult.create! attrs
136
- end
137
- end
138
- end
139
- # If the flight segment's aircraft_description doesn't contain '/' we can use
140
- # a method provided by loose_tight_dictionary to associate it with Aircraft
141
- else
142
- flight_segment.cache_aircraft!
143
- end
144
- end
145
- end
146
-
147
- # FIXME TODO do we want to restrict this to certain years?
148
- process "Derive some average characteristics from flight segments" do
149
- Aircraft.find_each do |aircraft|
150
- aircraft.seats = aircraft.flight_segments.weighted_average :seats_per_flight, :weighted_by => :passengers
151
- aircraft.passengers = aircraft.flight_segments.sum :passengers
152
- aircraft.save
153
- end
154
- end
155
-
142
+ process :update_averages!
143
+
156
144
  # FIXME TODO verify this
157
145
  end
158
146
  end
@@ -11,7 +11,7 @@ class AircraftClass < ActiveRecord::Base
11
11
  fuel_use_coefficients.all?(&:present?) and fuel_use_coefficients.any?(&:nonzero?)
12
12
  end
13
13
 
14
- create_table do
14
+ force_schema do
15
15
  string 'code'
16
16
  float 'm3'
17
17
  string 'm3_units'
@@ -20,7 +20,7 @@ class AircraftFuelUseEquation < ActiveRecord::Base
20
20
  fuel_use_coefficients.all?(&:present?) and fuel_use_coefficients.any?(&:nonzero?)
21
21
  end
22
22
 
23
- create_table do
23
+ force_schema do
24
24
  string 'code'
25
25
  string 'aircraft_description'
26
26
  float 'm3'
@@ -1,7 +1,7 @@
1
1
  class Airline < ActiveRecord::Base
2
2
  set_primary_key :name
3
3
 
4
- create_table do
4
+ force_schema do
5
5
  string 'name'
6
6
  string 'bts_code'
7
7
  string 'iata_code'
@@ -7,7 +7,7 @@ class Airport < ActiveRecord::Base
7
7
  :lat_column_name => :latitude,
8
8
  :lng_column_name => :longitude
9
9
 
10
- create_table do
10
+ force_schema do
11
11
  string 'iata_code'
12
12
  string 'name'
13
13
  string 'city'
@@ -1,6 +1,6 @@
1
1
  class BtsAircraft < ActiveRecord::Base
2
2
  set_primary_key :bts_code
3
- create_table do
3
+ force_schema do
4
4
  string 'bts_code'
5
5
  string 'description'
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class FlightDistanceClass < ActiveRecord::Base
2
2
  set_primary_key :name
3
- create_table do
3
+ force_schema do
4
4
  string 'name'
5
5
  float 'distance'
6
6
  string 'distance_units'
@@ -3,7 +3,7 @@ class FlightSeatClass < ActiveRecord::Base
3
3
 
4
4
  falls_back_on :multiplier => 1
5
5
 
6
- create_table do
6
+ force_schema do
7
7
  string 'name'
8
8
  string 'distance_class_name'
9
9
  string 'seat_class_name'
@@ -19,7 +19,7 @@ class FlightSegment < ActiveRecord::Base
19
19
  :load_factor => lambda { weighted_average(:load_factor, :weighted_by => :passengers) }, # 0.78073233770097 data1 10-12-2010
20
20
  :freight_share => lambda { weighted_average(:freight_share, :weighted_by => :passengers) } # 0.022567224170157 data1 10-12-2010
21
21
 
22
- create_table do
22
+ force_schema do
23
23
  string 'row_hash' # auto-generated primary key
24
24
  string 'origin_airport_iata_code' # iata code
25
25
  string 'origin_airport_city' # city
@@ -10,6 +10,24 @@ FlightSegment.class_eval do
10
10
  end
11
11
  end
12
12
 
13
+ def self.update_averages!
14
+ # Derive load factor, which is passengers divided by available seats
15
+ update_all 'load_factor = passengers / seats', 'seats > 0'
16
+
17
+ # Assume a load factor of 1 where passengers > available seats
18
+ update_all 'load_factor = 1', 'passengers > seats AND seats > 0'
19
+
20
+ # TODO: what is 90.718474
21
+ # Derive freight share as a fraction of the total weight carried
22
+ update_all 'freight_share = (freight + mail) / (freight + mail + (passengers * 90.718474))', '(freight + mail + passengers) > 0'
23
+
24
+ # Derive average seats per flight
25
+ update_all 'seats_per_flight = seats / flights', 'flights > 0'
26
+
27
+ # Add a useful date field
28
+ update_all 'approximate_date = DATE(CONCAT_WS("-", year, month, "14"))', 'month IS NOT NULL'
29
+ end
30
+
13
31
  URL = 'http://www.transtats.bts.gov/DownLoad_Table.asp?Table_ID=293&Has_Group=3&Is_Zipped=0'
14
32
  FORM_DATA = %{
15
33
  UserTableName=T_100_Segment__All_Carriers&
@@ -201,10 +219,10 @@ FlightSegment.class_eval do
201
219
  store 'flights', :field_name => 'DEPARTURES_PERFORMED'
202
220
  store 'passengers', :field_name => 'PASSENGERS'
203
221
  store 'seats', :field_name => 'SEATS'
204
- store 'payload_capacity', :field_name => 'PAYLOAD', :units => 'pounds'
205
- store 'freight', :field_name => 'FREIGHT', :units => 'pounds'
206
- store 'mail', :field_name => 'MAIL', :units => 'pounds'
207
- store 'distance', :field_name => 'DISTANCE', :units => 'miles'
222
+ store 'payload_capacity', :field_name => 'PAYLOAD', :from_units => :pounds, :to_units => :kilograms
223
+ store 'freight', :field_name => 'FREIGHT', :from_units => :pounds, :to_units => :kilograms
224
+ store 'mail', :field_name => 'MAIL', :from_units => :pounds, :to_units => :kilograms
225
+ store 'distance', :field_name => 'DISTANCE', :from_units => :miles, :to_units => :kilometres
208
226
  store 'month', :field_name => 'MONTH'
209
227
  store 'year', :field_name => 'YEAR'
210
228
  store 'source', :static => 'BTS T100'
@@ -232,49 +250,9 @@ FlightSegment.class_eval do
232
250
  end
233
251
  end
234
252
 
235
- %w{ payload_capacity freight mail }.each do |field|
236
- process "Convert #{field} from pounds to kilograms" do
237
- conversion_factor = 1.pounds.to(:kilograms)
238
- connection.execute %{
239
- UPDATE flight_segments
240
- SET #{field} = #{field} * #{conversion_factor},
241
- #{field + '_units'} = 'kilograms'
242
- WHERE #{field + '_units'} = 'pounds'
243
- }
244
- end
245
- end
246
-
247
- process "Convert distance from miles to kilometres" do
248
- conversion_factor = 1.miles.to(:kilometres)
249
- connection.execute %{
250
- UPDATE flight_segments
251
- SET distance = distance * #{conversion_factor},
252
- distance_units = 'kilometres'
253
- WHERE distance_units = 'miles'
254
- }
255
- end
256
-
257
- process "Derive load factor, which is passengers divided by available seats" do
258
- update_all 'load_factor = passengers / seats', 'seats > 0'
259
- end
260
-
261
- process "Assume a load factor of 1 where passengers > available seats" do
262
- update_all 'load_factor = 1', 'passengers > seats AND seats > 0'
263
- end
264
-
265
- process "Derive freight share as a fraction of the total weight carried" do
266
- update_all 'freight_share = (freight + mail) / (freight + mail + (passengers * 90.718474))', '(freight + mail + passengers) > 0'
267
- end
268
-
269
- process "Derive average seats per flight" do
270
- update_all 'seats_per_flight = seats / flights', 'flights > 0'
271
- end
272
-
273
- process "Add a useful date field" do
274
- update_all 'approximate_date = DATE(CONCAT_WS("-", year, month, "14"))', 'month IS NOT NULL'
275
- end
253
+ process :update_averages!
276
254
 
277
- process "Data mine Aircraft to cache fuzzy matches" do
255
+ process "Data mine Aircraft because it's like a belongs-to association" do
278
256
  Aircraft.run_data_miner!
279
257
  end
280
258
 
@@ -98,7 +98,7 @@ class AutomobileFuel < ActiveRecord::Base
98
98
  :hfc_emission_factor => lambda { AutomobileFuel.fallback_hfc_emission_factor },
99
99
  :hfc_emission_factor_units => lambda { AutomobileFuel.fallback_hfc_emission_factor_units }
100
100
 
101
- create_table do
101
+ force_schema do
102
102
  string 'name'
103
103
  string 'code'
104
104
  string 'base_fuel_name'