active_nutrition 0.5.0

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 (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: []