active_nutrition 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/lib/active-nutrition.rb +1 -0
  2. data/lib/active_nutrition.rb +99 -0
  3. data/lib/active_nutrition/migrations/00000000001_migrations_table.rb +18 -0
  4. data/lib/active_nutrition/migrations/00000000002_sr_24.rb +207 -0
  5. data/lib/active_nutrition/models.rb +19 -0
  6. data/lib/active_nutrition/models/data_src.rb +10 -0
  7. data/lib/active_nutrition/models/datsrcln.rb +14 -0
  8. data/lib/active_nutrition/models/deriv_cd.rb +10 -0
  9. data/lib/active_nutrition/models/fd_group.rb +10 -0
  10. data/lib/active_nutrition/models/food_des.rb +19 -0
  11. data/lib/active_nutrition/models/footnote.rb +10 -0
  12. data/lib/active_nutrition/models/langdesc.rb +10 -0
  13. data/lib/active_nutrition/models/langual.rb +13 -0
  14. data/lib/active_nutrition/models/migration.rb +9 -0
  15. data/lib/active_nutrition/models/nut_data.rb +22 -0
  16. data/lib/active_nutrition/models/nutr_def.rb +14 -0
  17. data/lib/active_nutrition/models/src_cd.rb +10 -0
  18. data/lib/active_nutrition/models/weight.rb +17 -0
  19. data/lib/active_nutrition/objects.rb +13 -0
  20. data/lib/active_nutrition/objects/base.rb +25 -0
  21. data/lib/active_nutrition/objects/food.rb +41 -0
  22. data/lib/active_nutrition/objects/food_group.rb +14 -0
  23. data/lib/active_nutrition/objects/nutrition_fact.rb +24 -0
  24. data/lib/active_nutrition/objects/nutrition_facts.rb +15 -0
  25. data/lib/active_nutrition/objects/weight.rb +15 -0
  26. data/lib/active_nutrition/objects/weights.rb +15 -0
  27. data/lib/active_nutrition/railtie.rb +29 -0
  28. data/lib/active_nutrition/utilities.rb +9 -0
  29. data/lib/active_nutrition/utilities/data_file.rb +68 -0
  30. data/lib/active_nutrition/utilities/unit_converter.rb +32 -0
  31. data/lib/active_nutrition/utilities/update.rb +100 -0
  32. data/lib/active_nutrition/utilities/usda_map.yml +119 -0
  33. data/lib/active_nutrition/version.rb +6 -0
  34. metadata +127 -0
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'active_nutrition')
@@ -0,0 +1,99 @@
1
+ # encoding: UTF-8
2
+
3
+ $:.push(File.dirname(__FILE__))
4
+ $:.push(File.dirname(File.dirname(__FILE__)))
5
+
6
+ $KCODE = 'UTF-8' unless RUBY_VERSION >= '1.9.0'
7
+
8
+ require 'open-uri'
9
+ require 'fileutils'
10
+ require 'yaml'
11
+
12
+ require 'rake'
13
+ require 'json'
14
+ require 'zip/zip'
15
+ require 'active_record'
16
+ require 'composite_primary_keys'
17
+
18
+ require 'active_nutrition/models'
19
+ require 'active_nutrition/objects'
20
+ require 'active_nutrition/utilities'
21
+ require 'active_nutrition/migrations/00000000001_migrations_table'
22
+
23
+ require 'active_nutrition/railtie' if defined?(Rails)
24
+
25
+ include ActiveNutrition::Models
26
+ include ActiveNutrition::Objects
27
+ include ActiveNutrition::Utilities
28
+
29
+ module ActiveNutrition
30
+ DEFAULT_SEARCH_LIMIT = 10
31
+
32
+ class << self
33
+ def migrate
34
+ current_migrations = Migration.find(:all).map(&:sequence_no)
35
+ rescue ActiveRecord::StatementInvalid => e
36
+ ActiveNutrition::Migrations::MigrationsTable.up
37
+ Migration.create(:sequence_no => 1)
38
+ current_migrations = Migration.find(:all).map(&:sequence_no)
39
+ ensure
40
+ next_migrations = migrations.reject { |file| (current_migrations || []).include?(File.basename(file)[0..11].to_i) }.sort
41
+ next_migrations.each do |file|
42
+ require file
43
+ migration_class = ActiveNutrition::Migrations.const_get(File.basename(file).split("_")[1..-1].map(&:capitalize).join("").chomp(".rb"))
44
+ migration_class.up
45
+ Migration.create(:sequence_no => File.basename(file)[0..11].to_i)
46
+ end
47
+ end
48
+
49
+ def update
50
+ raise "Not yet supported."
51
+ end
52
+
53
+ def rebuild
54
+ upd = Update.new(:type => :full)
55
+ puts "Downloading data..."
56
+ upd.download
57
+ puts "Extracting..."
58
+ upd.unzip
59
+ puts "Clearing tables..."
60
+ upd.reset_db
61
+ execute_update(upd)
62
+ puts "Done."
63
+ end
64
+
65
+ def search(terms = "", options = {})
66
+ options[:conditions] ||= ["Long_Desc LIKE ? OR Long_Desc LIKE ?", "%#{terms.gsub(" ", "%")}%", "%#{terms.split(" ").reverse.join("%")}%"]
67
+ options[:limit] ||= DEFAULT_SEARCH_LIMIT
68
+ Food.wrap(FoodDes.find(:all, options))
69
+ end
70
+
71
+ def get(ndb_no)
72
+ Food.wrap(FoodDes.find(ndb_no))
73
+ end
74
+
75
+ def convert(value, options = {})
76
+ UnitConverter.convert(value, options)
77
+ end
78
+
79
+ def supported_conversion?(options)
80
+ UnitConverter.supported_conversion?(options)
81
+ end
82
+
83
+ protected
84
+
85
+ def migrations
86
+ @migrations ||= Dir.glob(File.join(File.dirname(__FILE__), "active_nutrition/migrations/**/**.rb"))
87
+ end
88
+
89
+ def execute_update(updater)
90
+ last_model = nil
91
+ updater.execute do |model, record_count, record_total|
92
+ puts "" unless model == last_model
93
+ print "\rProcessing #{model}, #{record_count} / #{record_total} (#{((record_count.to_f / record_total.to_f) * 100).round}%) records imported"
94
+ STDOUT.flush
95
+ last_model = model
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Migrations
5
+ class MigrationsTable < ActiveRecord::Migration
6
+ def self.up
7
+ create_table :active_nutrition_migrations do |t|
8
+ t.integer :sequence_no
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :active_nutrition_migrations
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,207 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Migrations
5
+ class Sr24 < ActiveRecord::Migration
6
+ def self.up
7
+ create_table "abbrev", :primary_key => "NDB_No", :force => true do |t|
8
+ t.string "Shrt_Desc", :limit => 60
9
+ t.float "Water"
10
+ t.integer "Energ_Kcal"
11
+ t.float "Protein"
12
+ t.float "Lipid_Tot"
13
+ t.float "Ash"
14
+ t.float "Carbohydrt"
15
+ t.float "Fiber_TD"
16
+ t.float "Sugar_Tot", :default => 0.0
17
+ t.integer "Calcium"
18
+ t.float "Iron"
19
+ t.float "Magnesium", :default => 0.0
20
+ t.integer "Phosphorus"
21
+ t.integer "Potassium"
22
+ t.integer "Sodium"
23
+ t.float "Zinc", :default => 0.0
24
+ t.float "Copper", :default => 0.0
25
+ t.float "Manganese", :default => 0.0
26
+ t.float "Selenium", :default => 0.0
27
+ t.float "Vit_C"
28
+ t.float "Thiamin", :default => 0.0
29
+ t.float "Riboflavin", :default => 0.0
30
+ t.float "Niacin", :default => 0.0
31
+ t.float "Panto_Acid", :default => 0.0
32
+ t.float "Vit_B6", :default => 0.0
33
+ t.float "Folate_Tot", :default => 0.0
34
+ t.float "Folic_Acid", :default => 0.0
35
+ t.float "Food_Folate", :default => 0.0
36
+ t.float "Folate_DFE", :default => 0.0
37
+ t.float "Choline_Tot", :default => 0.0
38
+ t.float "Vit_B12", :default => 0.0
39
+ t.integer "Vit_A_IU"
40
+ t.float "Vit_A_RAE", :default => 0.0
41
+ t.float "Retinol", :default => 0.0
42
+ t.float "Alpha_Carot", :default => 0.0
43
+ t.float "Beta_Carot", :default => 0.0
44
+ t.float "Beta_Crypt", :default => 0.0
45
+ t.float "Lycopene", :default => 0.0
46
+ t.float "Lut+Zea", :default => 0.0
47
+ t.float "Vit_E", :default => 0.0
48
+ t.float "Vit_D_mcg", :default => 0.0
49
+ t.float "ViVit_D_IU", :default => 0.0
50
+ t.float "Vit_K", :default => 0.0
51
+ t.float "FA_Sat"
52
+ t.float "FA_Mono", :default => 0.0
53
+ t.float "FA_Poly", :default => 0.0
54
+ t.integer "Cholestrl"
55
+ t.float "GmWt_1"
56
+ t.string "GmWt_Desc1", :limit => 120
57
+ t.float "GmWt_2", :default => 0.0
58
+ t.string "GmWt_Desc2", :limit => 120
59
+ t.integer "Refuse_Pct"
60
+ end
61
+
62
+ add_index "abbrev", ["Folic_Acid"], :name => "Abbrev_Folic_Acid_Index"
63
+ add_index "abbrev", ["Panto_Acid"], :name => "Abbrev_Panto_Acid_Index"
64
+
65
+ create_table "data_src", :id => false, :primary_key => "DataSrc_ID", :force => true do |t|
66
+ t.integer "DataSrc_ID"
67
+ t.string "Authors"
68
+ t.string "Title"
69
+ t.string "Year", :limit => 4
70
+ t.string "Journal", :limit => 135
71
+ t.string "Vol_city", :limit => 16
72
+ t.string "Issue_State", :limit => 5
73
+ t.string "Start_Page", :limit => 5
74
+ t.string "End_Page", :limit => 5
75
+ end
76
+
77
+ add_index "data_src", ["DataSrc_ID"], :name => "DataSrc_ID_Index"
78
+
79
+ create_table "datsrcln", :id => false, :primary_key => "NDB_No", :force => true do |t|
80
+ t.integer "NDB_No", :null => false
81
+ t.integer "Nutr_No", :null => false
82
+ t.string "DataSrc_ID", :limit => 6, :null => false
83
+ end
84
+
85
+ add_index "datsrcln", ["NDB_No", "Nutr_No", "DataSrc_ID"], :name => "Datsrcln_NDB_No_Nutr_No_DataSrc_ID_Index", :unique => true
86
+
87
+ #create_table "deriv_cd", :primary_key => "Deriv_CD", :force => true do |t|
88
+ create_table "deriv_cd", :id => false, :primary_key => "Deriv_CD", :force => true do |t|
89
+ t.integer "Deriv_CD"
90
+ t.string "Deriv_Desc", :limit => 120
91
+ end
92
+
93
+ add_index "deriv_cd", ["Deriv_CD"], :name => "Deriv_CD_Deriv_CD_Index"
94
+
95
+ create_table "fd_group", :primary_key => "FdGrp_CD", :force => true do |t|
96
+ t.string "FdGrp_Desc", :limit => 60
97
+ end
98
+
99
+ create_table "food_des", :primary_key => "NDB_No", :force => true do |t|
100
+ t.string "FdGrp_Cd", :limit => 4
101
+ t.string "Long_Desc", :limit => 200
102
+ t.string "Shrt_Desc", :limit => 60
103
+ t.string "ComName", :limit => 100
104
+ t.string "ManufacName", :limit => 65
105
+ t.string "Survey", :limit => 1
106
+ t.string "Ref_Desc", :limit => 135
107
+ t.integer "Refuse"
108
+ t.string "SciName", :limit => 65
109
+ t.float "N_Factor"
110
+ t.float "Pro_Factor"
111
+ t.float "Fat_Factor"
112
+ t.float "CHO_Factor"
113
+ end
114
+
115
+ create_table "footnote", :id => false, :primary_key => "Footnt_No", :force => true do |t|
116
+ t.integer "NDB_No", :null => false
117
+ t.integer "Footnt_No"
118
+ t.string "Footnot_Typ", :limit => 1
119
+ t.integer "Nutr_No"
120
+ t.string "Footnot_Txt", :limit => 200
121
+ end
122
+
123
+ create_table "langdesc", :id => false, :primary_key => "Factor_Code", :force => true do |t|
124
+ t.string "Factor_Code"
125
+ t.string "Description", :limit => 250
126
+ end
127
+
128
+ add_index "langdesc", ["Factor_Code"], :name => "LangDesc_Factor_Code_Index"
129
+
130
+ create_table "langual", :id => false, :primary_key => "NDB_No", :force => true do |t|
131
+ t.integer "NDB_No", :null => false
132
+ t.string "Factor_Code", :limit => 6, :null => false
133
+ end
134
+
135
+ add_index "langual", ["NDB_No", "Factor_Code"], :name => "Langual_NDB_No_Factor_Code_Index", :unique => true
136
+
137
+ create_table "nut_data", :id => false, :primary_key => "NDB_No", :force => true do |t|
138
+ t.integer "NDB_No", :null => false
139
+ t.integer "Nutr_No", :null => false
140
+ t.float "Nutr_Val"
141
+ t.integer "Num_Data_Pts"
142
+ t.float "Std_Error"
143
+ t.string "Src_Cd", :limit => 2
144
+ t.string "Deriv_Cd", :limit => 4
145
+ t.integer "Ref_NDB_No"
146
+ t.string "Add_Nutr_Mark", :limit => 1
147
+ t.integer "Num_Studies"
148
+ t.float "Min"
149
+ t.float "Max"
150
+ t.float "DF"
151
+ t.float "Low_EB"
152
+ t.float "Up_EB"
153
+ t.string "Stat_Cmt", :limit => 10
154
+ t.date "AddMod_Date"
155
+ t.string "CC"
156
+ end
157
+
158
+ add_index "nut_data", ["NDB_No", "Nutr_No"], :name => "Nut_Data_NDB_No_Nutr_No_Index", :unique => true
159
+ add_index "nut_data", ["Num_Data_Pts"], :name => "Nut_Data_Num_Data_Pts_Index"
160
+ add_index "nut_data", ["Num_Studies"], :name => "Num_Studies_Index"
161
+
162
+ create_table "nutr_def", :primary_key => "Nutr_No", :force => true do |t|
163
+ t.string "Units", :limit => 7
164
+ t.string "Tagname", :limit => 20
165
+ t.string "NutrDesc", :limit => 60
166
+ t.string "Num_Dec", :limit => 1
167
+ t.float "SR_Order"
168
+ end
169
+
170
+ add_index "nutr_def", ["Num_Dec"], :name => "Num_Dec_Index"
171
+
172
+ create_table "src_cd", :primary_key => "Src_Cd", :force => true do |t|
173
+ t.string "SrcCd_Desc", :limit => 60
174
+ end
175
+
176
+ create_table "weight", :id => false, :primary_key => "NDB_No", :force => true do |t|
177
+ t.integer "NDB_No", :null => false
178
+ t.integer "Seq", :null => false
179
+ t.float "Amount"
180
+ t.string "Msre_Desc", :limit => 80
181
+ t.float "Gm_Wgt"
182
+ t.integer "Num_Data_Pts"
183
+ t.float "Std_Dev"
184
+ end
185
+
186
+ add_index "weight", ["NDB_No", "Seq"], :name => "Weight_NDB_No_Seq_Index", :unique => true
187
+ add_index "weight", ["Num_Data_Pts"], :name => "Weight_Num_Data_Pts_Index"
188
+ end
189
+
190
+ def self.down
191
+ drop_table "abbrev"
192
+ drop_table "data_src"
193
+ drop_table "datsrcln"
194
+ drop_table "deriv_cd"
195
+ drop_table "fd_group"
196
+ drop_table "food_des"
197
+ drop_table "footnote"
198
+ drop_table "langdesc"
199
+ drop_table "langual"
200
+ drop_table "nut_data"
201
+ drop_table "nutr_def"
202
+ drop_table "src_cd"
203
+ drop_table "weight"
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ autoload :Migration, 'active_nutrition/models/migration'
6
+ autoload :DataSrc, 'active_nutrition/models/data_src'
7
+ autoload :Datsrcln, 'active_nutrition/models/datsrcln'
8
+ autoload :DerivCd, 'active_nutrition/models/deriv_cd'
9
+ autoload :FdGroup, 'active_nutrition/models/fd_group'
10
+ autoload :FoodDes, 'active_nutrition/models/food_des'
11
+ autoload :Footnote, 'active_nutrition/models/footnote'
12
+ autoload :Langdesc, 'active_nutrition/models/langdesc'
13
+ autoload :Langual, 'active_nutrition/models/langual'
14
+ autoload :NutData, 'active_nutrition/models/nut_data'
15
+ autoload :NutrDef, 'active_nutrition/models/nutr_def'
16
+ autoload :SrcCd, 'active_nutrition/models/src_cd'
17
+ autoload :Weight, 'active_nutrition/models/weight'
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class DataSrc < ActiveRecord::Base
6
+ set_table_name "data_src"
7
+ set_primary_key :DataSrc_ID
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Datsrcln < ActiveRecord::Base
6
+ set_table_name "datsrcln"
7
+ set_primary_key :NDB_No
8
+
9
+ validates :NDB_No, :uniqueness => { :scope => [:Nutr_No, :DataSrc_ID] }
10
+ validates :Nutr_No, :uniqueness => { :scope => [:NDB_No, :DataSrc_ID] }
11
+ validates :DataSrc_ID, :uniqueness => { :scope => [:NDB_No, :Nutr_No] }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class DerivCd < ActiveRecord::Base
6
+ set_table_name "deriv_cd"
7
+ set_primary_key :Deriv_CD
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class FdGroup < ActiveRecord::Base
6
+ set_table_name "fd_group"
7
+ set_primary_key :FdGrp_CD
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class FoodDes < ActiveRecord::Base
6
+ set_table_name "food_des"
7
+ set_primary_key :NDB_No
8
+
9
+ alias_attribute :description, :Long_Desc
10
+ alias_attribute :common_name, :ComName
11
+ alias_attribute :manufacturer, :ManufacName
12
+
13
+ has_many :nutrition_facts, :class_name => "ActiveNutrition::Models::NutData", :foreign_key => "NDB_No", :primary_key => "NDB_No"
14
+ has_many :weights, :class_name => "ActiveNutrition::Models::Weight", :foreign_key => "NDB_No", :primary_key => "NDB_No"
15
+
16
+ belongs_to :food_group, :class_name => "ActiveNutrition::Models::FdGroup", :foreign_key => "FdGrp_Cd", :primary_key => "FdGrp_CD"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Footnote < ActiveRecord::Base
6
+ set_table_name "footnote"
7
+ set_primary_key :Footnt_No
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Langdesc < ActiveRecord::Base
6
+ set_table_name "langdesc"
7
+ set_primary_key :Factor_Code
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Langual < ActiveRecord::Base
6
+ set_table_name "langual"
7
+ set_primary_key :NDB_No
8
+
9
+ validates :NDB_No, :uniqueness => { :scope => [:Factor_Code] }
10
+ validates :Factor_Code, :uniqueness => { :scope => [:NDB_No] }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Migration < ActiveRecord::Base
6
+ set_table_name "active_nutrition_migrations"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class NutData < ActiveRecord::Base
6
+ set_table_name "nut_data"
7
+ set_primary_key :NDB_No
8
+
9
+ alias_attribute :value, :Nutr_Val
10
+
11
+ belongs_to :definition, :class_name => "ActiveNutrition::Models::NutrDef", :foreign_key => "Nutr_No", :primary_key => "Nutr_No"
12
+ validates :NDB_No, :uniqueness => { :scope => [:Nutr_No] }
13
+ validates :Nutr_No, :uniqueness => { :scope => [:NDB_No] }
14
+
15
+ # the value of Nutr_Val is the number of grams in 100 grams total,
16
+ # which it makes it easy to calculate the amount in every 1 gram
17
+ def amount_per_gram
18
+ return self.Nutr_Val.to_f / 100.0
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class NutrDef < ActiveRecord::Base
6
+ set_table_name "nutr_def"
7
+ set_primary_key :Nutr_No
8
+
9
+ alias_attribute :units, :Units
10
+ alias_attribute :name, :NutrDesc
11
+ alias_attribute :tag_name, :Tagname
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class SrcCd < ActiveRecord::Base
6
+ set_table_name "src_cd"
7
+ set_primary_key :Src_Cd
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Models
5
+ class Weight < ActiveRecord::Base
6
+ set_table_name "weight"
7
+ set_primary_key :NDB_No
8
+
9
+ validates :NDB_No, :uniqueness => { :scope => [:Seq] }
10
+ validates :Seq, :uniqueness => { :scope => [:NDB_No] }
11
+
12
+ alias_attribute :amount, :Amount
13
+ alias_attribute :grams, :Gm_Wgt
14
+ alias_attribute :measurement, :Msre_Desc
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ autoload :Base, 'active_nutrition/objects/base'
6
+ autoload :Food, 'active_nutrition/objects/food'
7
+ autoload :Weight, 'active_nutrition/objects/weight'
8
+ autoload :Weights, 'active_nutrition/objects/weights'
9
+ autoload :FoodGroup, 'active_nutrition/objects/food_group'
10
+ autoload :NutritionFact, 'active_nutrition/objects/nutrition_fact'
11
+ autoload :NutritionFacts, 'active_nutrition/objects/nutrition_facts'
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class Base
6
+ attr_reader :attributes, :base_model
7
+
8
+ def initialize(base_model)
9
+ @base_model = base_model
10
+ end
11
+
12
+ def attributes
13
+ base_model.attributes
14
+ end
15
+
16
+ def self.wrap(obj)
17
+ if obj.is_a?(Array)
18
+ obj.map { |o| new(o) }
19
+ else
20
+ new(obj)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class Food < Base
6
+ METHOD_MAP = { :name => :Long_Desc,
7
+ :ndb_number => :NDB_No,
8
+ :common_name => :ComName,
9
+ :manufacturers_name => :ManufacName,
10
+ :survey => :Survey,
11
+ :scientific_name => :SciName,
12
+ :fat_factor => :Fat_Factor,
13
+ :protein_factor => :Pro_Factor }
14
+
15
+ METHOD_MAP.each_pair do |method, attr_name|
16
+ define_method(method) { attributes[attr_name.to_s] }
17
+ end
18
+
19
+ attr_reader :food_group, :nutrition_facts
20
+
21
+ def food_group
22
+ @food_group ||= FoodGroup.new(base_model.food_group)
23
+ end
24
+
25
+ def nutrition_facts
26
+ @nutrition_facts ||= NutritionFacts.new(NutritionFact.wrap(base_model.nutrition_facts))
27
+ end
28
+
29
+ def weights
30
+ @weights ||= Weights.new(Weight.wrap(base_model.weights))
31
+ end
32
+
33
+ def factors
34
+ [:fat_factor, :protein_factor].inject({}) do |ret, factor|
35
+ ret[factor] = attributes[METHOD_MAP[factor].to_s]
36
+ ret
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class FoodGroup < Base
6
+ METHOD_MAP = { :name => :FdGrp_Desc,
7
+ :code => :FdGrp_CD }
8
+
9
+ METHOD_MAP.each_pair do |method, attr_name|
10
+ define_method(method) { attributes[attr_name.to_s] }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class NutritionFact < Base
6
+ METHOD_MAP = { :nutrition_number => :Nutr_No,
7
+ :value => :Nutr_Val,
8
+ :num_data_points => :Num_Data_Pts,
9
+ :standard_error => :Std_Error,
10
+ :units => :Units,
11
+ :description => :NutrDesc,
12
+ :tag_name => :Tagname,
13
+ :sr_order => :SR_Order }
14
+
15
+ METHOD_MAP.each_pair do |method, attr_name|
16
+ define_method(method) { self.attributes[attr_name.to_s] }
17
+ end
18
+
19
+ def attributes
20
+ @attributes ||= base_model.attributes.merge(base_model.definition.attributes)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class NutritionFacts < Array
6
+ def to_hash(options = {})
7
+ options[:by] ||= :description
8
+ inject({}) do |ret, fact|
9
+ ret[fact.send(options[:by])] = fact.value
10
+ ret
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class Weight < Base
6
+ METHOD_MAP = { :amount => :Amount,
7
+ :grams => :Gm_Wgt,
8
+ :measurement => :Msre_Desc }
9
+
10
+ METHOD_MAP.each_pair do |method, attr_name|
11
+ define_method(method) { self.attributes[attr_name.to_s] }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Objects
5
+ class Weights < Array
6
+ def to_hash(options = {})
7
+ options[:by] ||= :measurement
8
+ inject({}) do |ret, weight|
9
+ ret[weight.send(options[:by])] = weight.grams
10
+ ret
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+
3
+ include Rake::DSL
4
+
5
+ module ActiveNutrition
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ namespace :active_nutrition do
9
+ task :migrate => :environment do
10
+ ActiveNutrition.migrate
11
+ end
12
+
13
+ task :update => :environment do
14
+ raise "Not yet supported."
15
+ end
16
+
17
+ task :rebuild => :environment do
18
+ ActiveNutrition.rebuild
19
+ end
20
+ end
21
+
22
+ namespace :an do
23
+ task :migrate => "active_nutrition:migrate"
24
+ task :update => "active_nutrition:update"
25
+ task :rebuild => "active_nutrition:rebuild"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Utilities
5
+ autoload :DataFile, 'active_nutrition/utilities/data_file'
6
+ autoload :Update, 'active_nutrition/utilities/update'
7
+ autoload :UnitConverter, 'active_nutrition/utilities/unit_converter'
8
+ end
9
+ end
@@ -0,0 +1,68 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Utilities
5
+ class DataFile
6
+ attr_reader :file, :handle
7
+
8
+ FIELD_SEP = '^'
9
+ FIELD_ENC = '~'
10
+ NULL_FIELDS = ['^^', '~~', "\r\n", '']
11
+
12
+ def initialize(file)
13
+ @file = file
14
+ @handle = File.open(file, "r")
15
+ end
16
+
17
+ def each
18
+ @handle.each do |line|
19
+ yield self.parse_line(line)
20
+ end
21
+ self.clean_up
22
+ end
23
+
24
+ protected
25
+
26
+ def clean_up
27
+ @handle.close
28
+ end
29
+
30
+ def parse_line(line)
31
+ line.force_encoding("ISO-8859-1")
32
+ #line.byte_size = 8
33
+ line.chomp!("\r\n")
34
+ fields = line.split('^')
35
+ p_fields = []
36
+
37
+ fields.each do |field|
38
+ # strip the '~' if present
39
+ if field.index('"')
40
+ field.gsub!(/[\"]/, "'")
41
+ end
42
+
43
+ if field.index(FIELD_ENC) && field.size > 2
44
+ p_fields << field[1..-2]
45
+ else
46
+ # else if the field matches a null field
47
+ if NULL_FIELDS.include?(field)
48
+ p_fields << ''
49
+ elsif field.include?('.')
50
+ # else the field must be a number
51
+ p_fields << field.to_f
52
+ elsif field.include?('/')
53
+ # check to see if its a date, add as a string for now
54
+ p_fields << field
55
+ else
56
+ p_fields << field.to_i
57
+ end
58
+ end
59
+ end
60
+ p_fields
61
+ rescue => e
62
+ puts line
63
+ puts e.message
64
+ puts e.backtrace
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Utilities
5
+ class UnitConverter
6
+ CONVERSIONS = {
7
+ :oz => { :lb => 16.0 }, # i.e. to convert from pounds to ounces, multiply by 16 (because there are 16 ounces per pound)
8
+ :lb => { :oz => 1.0/16.0 },
9
+ :tsp => { :tbsp => 3.0, :cup => 48.0, :pint => 96.0, :quart => 192.0, :gallon => 768.0 },
10
+ :tbsp => { :tsp => 1.0/3.0, :cup => 16.0, :pint => 32.0, :quart => 64.0, :gallon => 256.0 },
11
+ :cup => { :tsp => 1.0/48.0, :tbsp => 1.0/16.0, :pint => 2.0, :quart => 4.0, :gallon => 16.0 },
12
+ :pint => { :tsp => 1.0/96.0, :tbsp => 1.0/32.0, :cup => 1.0/2.0, :quart => 2.0, :gallon => 8.0 },
13
+ :quart => { :tsp => 1.0/192.0, :tbsp => 1.0/64.0, :cup => 1.0/4.0, :pint => 1.0/2.0, :gallon => 4.0 },
14
+ :gallon => { :tsp => 1.0/768.0, :tbsp => 1.0/256.0, :cup => 1.0/16.0, :pint => 1.0/8.0, :quart => 1.0/4.0 }
15
+ }
16
+
17
+ class << self
18
+ def convert(value, options = {})
19
+ unless supported_conversion?(options)
20
+ raise "Conversion not supported - are you trying to convert weight to volume?"
21
+ end
22
+
23
+ value * CONVERSIONS[options[:to]][options[:from]]
24
+ end
25
+
26
+ def supported_conversion?(options = {})
27
+ CONVERSIONS.include?(options[:to]) && CONVERSIONS[options[:to]].include?(options[:from])
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ module Utilities
5
+ class Update
6
+ BASE_URL = "http://www.ars.usda.gov/"
7
+ BASE_PATH = "SP2UserFiles/Place/12354500/Data/SR{{release}}/dnload/"
8
+ FULL_FILE = "sr{{release}}.zip"
9
+ UPDATE_FILE = "sr{{release}}upd.zip"
10
+ CURRENT_RELEASE = ActiveNutrition::USDA_VERSION
11
+ DATA_DIR = File.join(File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))), "data")
12
+ IMPORT_CHUNK_SIZE = 1000
13
+
14
+ def initialize(options = {})
15
+ @release = (options[:release] || CURRENT_RELEASE).to_s
16
+ @usda_map = YAML::load_file(File.join(File.dirname(__FILE__), "usda_map.yml"))
17
+ @type = options[:type] || :update
18
+ @path, @file = self.url_for(@type)
19
+ @zip_file = File.join(DATA_DIR, @file)
20
+ @zip_dir = @zip_file.chomp(File.extname(@zip_file))
21
+ end
22
+
23
+ def execute
24
+ @usda_map.each_pair do |model_const, data|
25
+ if ActiveNutrition::Models.const_defined?(model_const.to_sym)
26
+ model = ActiveNutrition::Models.const_get(model_const.to_sym)
27
+ cur_file = File.join(@zip_dir, data["file_name"])
28
+ parser = DataFile.new(cur_file)
29
+ record_total = `wc -l "#{cur_file}"`.to_i
30
+ record_count = 0
31
+
32
+ parser.each do |values|
33
+ new_record = model.new
34
+
35
+ data["attribute_order"].each_with_index do |field, index|
36
+ # update each attribute by explicitly calling the attr= method, just in case
37
+ # there are custom methods in the model class
38
+ new_record.send(:"#{field}=", values[index])
39
+ end
40
+
41
+ new_record.save!
42
+
43
+ if record_count % IMPORT_CHUNK_SIZE == 0 || (record_count + 1) == record_total || record_count == 0
44
+ yield [model.to_s, record_count, record_total] if block_given?
45
+ end
46
+
47
+ record_count += 1
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def reset_db
54
+ @usda_map.each_key do |model_const|
55
+ if ActiveNutrition::Models.const_defined?(model_const.to_sym)
56
+ ActiveNutrition::Models.const_get(model_const.to_sym).delete_all
57
+ end
58
+ end
59
+ end
60
+
61
+ def clean
62
+ File.unlink(@zip_file) if File.exist?(@zip_file)
63
+ FileUtils.rm_rf(@zip_dir) if File.exist?(@zip_dir)
64
+ end
65
+
66
+ def download
67
+ unless File.file?(File.join(DATA_DIR, @file))
68
+ FileUtils.mkdir_p(DATA_DIR)
69
+ File.open(File.join(DATA_DIR, @file), "wb") do |f|
70
+ f.sync = true
71
+ f.write(open("#{BASE_URL}#{@path}#{@file}").read)
72
+ end
73
+ end
74
+ end
75
+
76
+ def unzip
77
+ Zip::ZipFile.open(@zip_file) do |zip_file|
78
+ zip_file.each do |f|
79
+ next unless f.file?
80
+ f_path = File.join(@zip_dir, f.name)
81
+ FileUtils.mkdir_p(File.dirname(f_path))
82
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
83
+ end
84
+ end
85
+ end
86
+
87
+ protected
88
+
89
+ def url_for(type = :full)
90
+ file = case type
91
+ when :full then FULL_FILE
92
+ when :update then UPDATE_FILE
93
+ else UPDATE_FILE
94
+ end
95
+
96
+ [BASE_PATH.gsub("{{release}}", @release), file.gsub("{{release}}", @release)]
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,119 @@
1
+ FoodDes:
2
+ file_name: FOOD_DES.txt
3
+ attribute_order:
4
+ - NDB_No
5
+ - FdGrp_Cd
6
+ - Long_Desc
7
+ - Shrt_Desc
8
+ - ComName
9
+ - ManufacName
10
+ - Survey
11
+ - Ref_Desc
12
+ - Refuse
13
+ - SciName
14
+ - N_Factor
15
+ - Pro_Factor
16
+ - Fat_Factor
17
+ - CHO_Factor
18
+
19
+ NutData:
20
+ file_name: NUT_DATA.txt
21
+ attribute_order:
22
+ - NDB_No
23
+ - Nutr_No
24
+ - Nutr_Val
25
+ - Num_Data_Pts
26
+ - Std_Error
27
+ - Src_Cd
28
+ - Deriv_Cd
29
+ - Ref_NDB_No
30
+ - Add_Nutr_Mark
31
+ - Num_Studies
32
+ - Min
33
+ - Max
34
+ - DF
35
+ - Low_EB
36
+ - Up_EB
37
+ - Stat_Cmt
38
+ - AddMod_Date
39
+ - CC
40
+
41
+ Weight:
42
+ file_name: WEIGHT.txt
43
+ attribute_order:
44
+ - NDB_No
45
+ - Seq
46
+ - Amount
47
+ - Msre_Desc
48
+ - Gm_Wgt
49
+ - Num_Data_Pts
50
+ - Std_Dev
51
+
52
+ Footnote:
53
+ file_name: FOOTNOTE.txt
54
+ attribute_order:
55
+ - NDB_No
56
+ - Footnt_No
57
+ - Footnot_Typ
58
+ - Nutr_No
59
+ - Footnot_Txt
60
+
61
+ FdGroup:
62
+ file_name: FD_GROUP.txt
63
+ attribute_order:
64
+ - FdGrp_CD
65
+ - FdGrp_Desc
66
+
67
+ Langual:
68
+ file_name: LANGUAL.txt
69
+ attribute_order:
70
+ - NDB_No
71
+ - Factor_Code
72
+
73
+ Langdesc:
74
+ file_name: LANGDESC.txt
75
+ attribute_order:
76
+ - Factor_Code
77
+ - Description
78
+
79
+ NutrDef:
80
+ file_name: NUTR_DEF.txt
81
+ attribute_order:
82
+ - Nutr_No
83
+ - Units
84
+ - Tagname
85
+ - NutrDesc
86
+ - Num_Dec
87
+ - SR_Order
88
+
89
+ SrcCd:
90
+ file_name: SRC_CD.txt
91
+ attribute_order:
92
+ - Src_Cd
93
+ - SrcCd_Desc
94
+
95
+ DerivCd:
96
+ file_name: DERIV_CD.txt
97
+ attribute_order:
98
+ - Deriv_CD
99
+ - Deriv_Desc
100
+
101
+ DataSrc:
102
+ file_name: DATA_SRC.txt
103
+ attribute_order:
104
+ - DataSrc_ID
105
+ - Authors
106
+ - Title
107
+ - Year
108
+ - Journal
109
+ - Vol_city
110
+ - Issue_State
111
+ - Start_Page
112
+ - End_Page
113
+
114
+ Datsrcln:
115
+ file_name: DATSRCLN.txt
116
+ attribute_order:
117
+ - NDB_No
118
+ - Nutr_No
119
+ - DataSrc_ID
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ module ActiveNutrition
4
+ VERSION = "0.5.0"
5
+ USDA_VERSION = "24"
6
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_nutrition
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cameron Dutro
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rubyzip
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: composite_primary_keys
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 4.1.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 4.1.2
62
+ description: Updates, maintains, and provides systematic access to USDA nutrition
63
+ data. See lib/examples to get started.
64
+ email:
65
+ - camertron@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/active-nutrition.rb
71
+ - lib/active_nutrition/migrations/00000000001_migrations_table.rb
72
+ - lib/active_nutrition/migrations/00000000002_sr_24.rb
73
+ - lib/active_nutrition/models/data_src.rb
74
+ - lib/active_nutrition/models/datsrcln.rb
75
+ - lib/active_nutrition/models/deriv_cd.rb
76
+ - lib/active_nutrition/models/fd_group.rb
77
+ - lib/active_nutrition/models/food_des.rb
78
+ - lib/active_nutrition/models/footnote.rb
79
+ - lib/active_nutrition/models/langdesc.rb
80
+ - lib/active_nutrition/models/langual.rb
81
+ - lib/active_nutrition/models/migration.rb
82
+ - lib/active_nutrition/models/nut_data.rb
83
+ - lib/active_nutrition/models/nutr_def.rb
84
+ - lib/active_nutrition/models/src_cd.rb
85
+ - lib/active_nutrition/models/weight.rb
86
+ - lib/active_nutrition/models.rb
87
+ - lib/active_nutrition/objects/base.rb
88
+ - lib/active_nutrition/objects/food.rb
89
+ - lib/active_nutrition/objects/food_group.rb
90
+ - lib/active_nutrition/objects/nutrition_fact.rb
91
+ - lib/active_nutrition/objects/nutrition_facts.rb
92
+ - lib/active_nutrition/objects/weight.rb
93
+ - lib/active_nutrition/objects/weights.rb
94
+ - lib/active_nutrition/objects.rb
95
+ - lib/active_nutrition/railtie.rb
96
+ - lib/active_nutrition/utilities/data_file.rb
97
+ - lib/active_nutrition/utilities/unit_converter.rb
98
+ - lib/active_nutrition/utilities/update.rb
99
+ - lib/active_nutrition/utilities/usda_map.yml
100
+ - lib/active_nutrition/utilities.rb
101
+ - lib/active_nutrition/version.rb
102
+ - lib/active_nutrition.rb
103
+ homepage: http://github.com/camertron
104
+ licenses: []
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project: active_nutrition
123
+ rubygems_version: 1.8.24
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: USDA nutrition data
127
+ test_files: []