dietary_dsl 0.1.2

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.
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Módulo que agrupa las constantes y funciones útiles respecto a la base de datos BEDCA
5
+ module BEDCA
6
+ ATTRIBUTES = {
7
+ # Identificador
8
+ # 12
9
+ 'f_id' => :id,
10
+ # Nombre en español
11
+ # Arroz
12
+ 'f_ori_name' => :nombre,
13
+ # Nombre en inglés
14
+ # Rice
15
+ 'f_eng_name' => :name,
16
+ # Nombre científico
17
+ # Oryza sativa
18
+ 'sci_name' => :scientific_name,
19
+ # A0696 A0730 A0814 A0960 A1240 A1290 B1322 C0155 E0131 F0003 G0003 H0003 H0398 J0003 K0004 M0128 N0036 P0024...
20
+ 'langual' => :langual,
21
+ # Código en la base de datos EFSA, http://iufost.org/databases, https://www.efsa.europa.eu/en/efsajournal/pub/1970
22
+ # A001D
23
+ 'foodexcode' => :foodexcode,
24
+ # 11
25
+ 'mainlevelcode' => :mainlevelcode,
26
+ # Código de primer nivel de FoodEx
27
+ # A000J
28
+ 'codlevel1' => :codlevel1,
29
+ # Nombre del primer nivel de FoodEx
30
+ # Grains and grain-based products
31
+ 'namelevel1' => :namelevel1,
32
+ # 29
33
+ 'codsublevel' => :codsublevel,
34
+ # Código de segundo nivel de FoodEx
35
+ # A000K
36
+ 'codlevel2' => :codlevel2,
37
+ # Nombre del primer nivel de FoodEx
38
+ # Grains and grain-based products
39
+ 'namelevel2' => :namelevel2,
40
+ # ???
41
+ # null
42
+ 'f_des_esp' => :f_des_esp,
43
+ # ???
44
+ # null
45
+ 'f_des_ing' => :f_des_ing,
46
+ # ???
47
+ # URL de la imagen
48
+ 'photo' => :photo,
49
+ # ???
50
+ # null
51
+ 'edible_portion' => :edible_portion,
52
+ # Origen de la información
53
+ # BEDCA2
54
+ 'f_origen' => :f_origen,
55
+ # Valores nutricionales del alimento
56
+ # Array de componentes
57
+ 'foodvalue' => :foodvalue,
58
+
59
+ # =======================================================================
60
+ # Components
61
+ # =======================================================================
62
+ # Identificador
63
+ # 53
64
+ 'c_id' => :id,
65
+ # Nombre en español
66
+ # carbohidratos
67
+ 'c_ori_name' => :nombre,
68
+ # Nombre en inglés
69
+ # carbohydrate
70
+ 'c_eng_name' => :name,
71
+ # ???
72
+ # CHO
73
+ 'eur_name' => :eur_name,
74
+ # ???
75
+ # 2
76
+ 'componentgroup_id' => :componentgroup_id,
77
+ # Glosario del componente en español
78
+ # Este componente es uno de losmacronutrientes e incluye todos los hidratos de carbono
79
+ 'glos_esp' => :glos_esp,
80
+ # Glosario del componente en español
81
+ # null
82
+ 'glos_ing' => :glos_ing,
83
+ # Descripción del grupo de componentes en español
84
+ # Hidratos de carbono
85
+ 'cg_descripcion' => :categoria,
86
+ # Descripción del grupo de componentes en inglés
87
+ # Carbohydrate components
88
+ 'cg_description' => :cg_description,
89
+ # Cantidad de materia que contiene el elemento consultado
90
+ # 86
91
+ 'best_location' => :cantidad,
92
+ # Unidad de medida
93
+ # g
94
+ 'v_unit' => :unidad,
95
+ # ???
96
+ # W
97
+ 'moex' => :moex,
98
+ # ???
99
+ # null
100
+ 'stdv' => :stdv,
101
+ # ???
102
+ # null
103
+ 'min' => :min,
104
+ # ???
105
+ # null
106
+ 'max' => :max,
107
+ # ???
108
+ # null
109
+ 'v_n' => :v_n,
110
+ # Identificador de unidad de medición
111
+ # g
112
+ 'u_id' => :u_id,
113
+ # Descripción de la unidad de medición en español
114
+ # gramos
115
+ 'u_descripcion' => :u_descripcion,
116
+ # Descripción de la unidad de medición en inglés
117
+ # gram
118
+ 'u_description' => :u_description,
119
+ # ???
120
+ # AR
121
+ 'value_type' => :value_type,
122
+ # Descripción del tipo de valor en español
123
+ # como aparece en la fuente
124
+ 'vt_descripcion' => :vt_descripcion,
125
+ # Descripción del tipo de valor en inglés
126
+ # as reported
127
+ 'vt_description' => :vt_description,
128
+ # ???
129
+ # W
130
+ 'mu_id' => :mu_id,
131
+ # ???
132
+ # por 100 g de porción comestible
133
+ 'mu_descripcion' => :mu_descripcion,
134
+ # ???
135
+ # per 100 g edible portion
136
+ 'mu_description' => :mu_description,
137
+ # ???
138
+ # 258
139
+ 'ref_id' => :ref_id,
140
+ # ???
141
+ # null
142
+ 'citation' => :citation,
143
+ # ???
144
+ # tabla de composición de alimentos
145
+ 'at_descripcion' => :at_descripcion,
146
+ # ???
147
+ # food composition table
148
+ 'at_description' => :at_description,
149
+ # ???
150
+ # libro
151
+ 'pt_descripcion' => :pt_descripcion,
152
+ # ???
153
+ # book
154
+ 'pt_description' => :pt_description,
155
+ # ???
156
+ # 344
157
+ 'method_id' => :method_id,
158
+ # ???
159
+ # tipo de método no conocido
160
+ 'mt_descripcion' => :mt_descripcion,
161
+ # ???
162
+ # method type not known
163
+ 'mt_description' => :mt_description,
164
+ # ???
165
+ # Extraccion: Alicuotas del alimento (entre 5 y 30 g) dependiendo del color son...
166
+ 'm_descripcion' => :m_descripcion,
167
+ # ???
168
+ # null
169
+ 'm_description' => :m_description,
170
+ # ???
171
+ # Método no conocido (Moreiras)
172
+ 'm_nom_esp' => :m_nom_esp,
173
+ # ???
174
+ # Unknown method (Moreiras)
175
+ 'm_nom_ing' => :m_nom_ing,
176
+ # ???
177
+ # Metodo analitico o de cálculo no conocido
178
+ 'mhd_descripcion' => :mhd_descripcion,
179
+ # ???
180
+ # Analytical or calculation method not known
181
+ 'mhd_description' => :mhd_description
182
+ }.freeze
183
+ end
184
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Módulo que agrupa las constantes y funciones útiles respecto a la base de datos BEDCA
5
+ module BEDCA
6
+ CATEGORIES = {
7
+ 'Hidratos de Carbono' => :hidratos_de_carbono,
8
+ 'Vitaminas' => :vitaminas,
9
+ 'Grasas' => :grasas,
10
+ 'Minerales' => :minerales,
11
+ 'Proximales' => :proximales
12
+ }.freeze
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Módulo que agrupa las constantes y funciones útiles respecto a la base de datos BEDCA
5
+ module BEDCA
6
+ COMPONENTS = {
7
+ '53' => :carbohidratos,
8
+ '67' => :carotenoides_totales,
9
+ '88' => :retinol,
10
+ '100' => :vitamina_a,
11
+ '102' => :vitamina_d,
12
+ '103' => :viamina_e,
13
+ '123' => :acido_graso_miristico,
14
+ '136' => :acido_graso_palmitico,
15
+ '157' => :acido_graso_estearico,
16
+ '172' => :acido_graso_oleico,
17
+ '189' => :acido_graso,
18
+ '199' => :acido_graso_alt,
19
+ '230' => :acido_graso_araquidonico,
20
+ '231' => :acido_graso_eicosapentaenoico,
21
+ '260' => :acido_graso_docosahexaenoico,
22
+ '282' => :acidos_grasos_monoinsaturados_totales,
23
+ '287' => :acidos_grasos_poliinsaturados_totales,
24
+ '299' => :acidos_grasos_saturados_totales,
25
+ '307' => :fibra_dietetica_total,
26
+ '317' => :calcio,
27
+ '319' => :hierro_total,
28
+ '321' => :potasio,
29
+ '322' => :magnesio,
30
+ '323' => :sodio,
31
+ '326' => :fosforo,
32
+ '404' => :alcohol,
33
+ '409' => :energia_total,
34
+ '410' => :grasa_total,
35
+ '416' => :proteina_total,
36
+ '417' => :agua,
37
+ '433' => :colesterol,
38
+ '456' => :ioduro,
39
+ '462' => :selenio_total,
40
+ '464' => :zinc,
41
+ '472' => :folato,
42
+ '475' => :equivalentes_de_niacina_totales,
43
+ '482' => :riboflavina,
44
+ '483' => :tiamina,
45
+ '484' => :vitamina_b_12,
46
+ '485' => :vitamina_b_6,
47
+ '486' => :vitamina_c,
48
+ '487' => :acido_folico,
49
+ 'alcohol (etanol)' => :alcohol,
50
+ 'grasa, total (lipidos totales)' => :grasa_total,
51
+ 'proteina, total' => :proteina_total,
52
+ 'carbohidratos' => :carbohidratos
53
+ }.freeze
54
+ end
55
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Módulo que agrupa las constantes y funciones útiles respecto a la base de datos BEDCA
5
+ module BEDCA
6
+ RELATIONS = {
7
+ equal: 'EQUAL',
8
+ like: 'LIKE'
9
+ }.freeze
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Módulo que agrupa las constantes y funciones útiles respecto a la base de datos BEDCA
5
+ module BEDCA
6
+ XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>'
7
+ URL = URI 'http://www.bedca.net/bdpub/procquery.php'
8
+ SVG_REGEX = %r{<text.+?>(?<value>.+?)</\s?text>.+?<text.+?>(?<label>.+?)</\s?text>}
9
+
10
+ def rehash(data, map = ATTRIBUTES)
11
+ data.each_with_object({}) do |(key, value), hash|
12
+ hash[map[key]] = value
13
+ hash
14
+ end
15
+ end
16
+
17
+ def arr_to_hash(data, map)
18
+ data.each_with_object({}) do |item, hash|
19
+ a = yield item
20
+ hash[map[a]] = item
21
+ hash
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/bedca_api/constants/attributes'
4
+ require 'dietary_dsl/bedca_api/constants/components'
5
+ require 'dietary_dsl/bedca_api/constants/relations'
6
+ require 'dietary_dsl/bedca_api/constants/categories'
7
+ require 'dietary_dsl/bedca_api/constants/utils'
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'builder'
6
+ require 'active_support/all'
7
+ require 'dietary_dsl/bedca_api/constants'
8
+ require 'dietary_dsl/bedca_api/food_value'
9
+ require 'dietary_dsl/bedca_api/food_values'
10
+ require 'pp'
11
+
12
+ module DietaryDsl
13
+ # Class that wraps Bedca database API
14
+ class Food
15
+ attr_reader :raw, :nombre, :name, :values
16
+
17
+ include BEDCA
18
+
19
+ @http = Net::HTTP.new(URL.host, URL.port)
20
+
21
+ class << self
22
+ attr_accessor :http
23
+ end
24
+
25
+ def self.request(xml)
26
+ response = @http.request_post URL, XML_HEADER + xml, 'Content-Type' => 'text/xml'
27
+ body = response.read_body
28
+ return Hash.from_xml body
29
+ rescue
30
+ raise 'Hay un problema con la conexión'
31
+ end
32
+
33
+ def self.sanitize_response(response)
34
+ response.dig 'foodresponse', 'food'
35
+ end
36
+
37
+ def self.build_attributes(b, attributes)
38
+ attributes
39
+ .reject { |(key)| key == 'foodvalue' }
40
+ .each do |(key)|
41
+ b.atribute name: key
42
+ end
43
+ end
44
+
45
+ def self.query(attributes = ATTRIBUTES)
46
+ Builder::XmlMarkup.new.foodquery do |b|
47
+ b.type level: 2
48
+ b.selection do
49
+ build_attributes(b, attributes)
50
+ end
51
+ yield b
52
+ end
53
+ end
54
+
55
+ def self.where(b, field, relation, value)
56
+ b.condition do
57
+ b.cond1 do
58
+ b.atribute1(name: ATTRIBUTES.key(field))
59
+ end
60
+ b.relation(type: relation)
61
+ b.cond3(value)
62
+ end
63
+ end
64
+
65
+ def self.find_by_and_relation(data, relation)
66
+ xml = query do |b|
67
+ data.each do |(key), value|
68
+ where(b, key, relation, value)
69
+ end
70
+ end
71
+
72
+ data = sanitize_response request xml
73
+ return nil if data.nil?
74
+
75
+ Food.new(data)
76
+ end
77
+
78
+ def self.find(id)
79
+ find_by(id: id)
80
+ end
81
+
82
+ def self.find_by(data)
83
+ find_by_and_relation(data, RELATIONS[:equal])
84
+ end
85
+
86
+ def self.find_by_like(data)
87
+ find_by_and_relation(data, RELATIONS[:like])
88
+ end
89
+
90
+ def initialize(values)
91
+ @data = rehash(values)
92
+ @groups = @data[:foodvalue]
93
+ .group_by { |value| value['cg_descripcion'] }
94
+ .each_with_object({}) do |(key, vals), hash|
95
+ hash[CATEGORIES[key]] = FoodValues.new(vals.first['cg_descripcion'], vals)
96
+ end
97
+
98
+ @data.delete(:foodvalue)
99
+ @data[:groups] = @groups
100
+
101
+ @general_values = download_general_values
102
+ end
103
+
104
+ def [](key)
105
+ @data[key]
106
+ end
107
+
108
+ def download_general_values
109
+ body = (Food.http.request_get "http://www.bedca.net/cocoon/svg/response#{self[:id]}langes.svg").read_body
110
+ parse_svg body
111
+ end
112
+
113
+ def parse_svg(svg)
114
+ (svg.scan SVG_REGEX).each_with_object({}) do |value, hash|
115
+ hash[COMPONENTS[value.last]] = value.first.delete(' ')
116
+ hash
117
+ end
118
+ end
119
+
120
+ def to_s
121
+ tables = @data[:groups]
122
+ .map do |(_key, group)|
123
+ group.to_table
124
+ end
125
+ .join("\n")
126
+
127
+ <<~TO_MARKDOWN
128
+ # #{self[:nombre]}
129
+
130
+ > #{self[:scientific_name]}
131
+
132
+ ## Distribución de la Energía total
133
+
134
+ Proteínas: #{@general_values[:proteina_total]}
135
+ Grasas: #{@general_values[:grasa_total]}
136
+ Carbohidratos: #{@general_values[:carbohidratos]}
137
+ Alcohol: #{@general_values[:alcohol]}
138
+
139
+ ## Información de composición (por 100 g de porción comestible)
140
+
141
+ #{tables}
142
+ TO_MARKDOWN
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/bedca_api/constants'
4
+
5
+ module DietaryDsl
6
+ # Clase que representa un tipo de valor nutricional y sus datos
7
+ class FoodValue
8
+ include BEDCA
9
+
10
+ def initialize(values)
11
+ data = rehash(values)
12
+
13
+ @data = data
14
+ end
15
+
16
+ def [](key)
17
+ return cantidad if key == :cantidad
18
+ @data[key]
19
+ end
20
+
21
+ def cantidad
22
+ @data[:cantidad] || @data[:vt_descripcion]
23
+ end
24
+
25
+ def to_s
26
+ "#{self[:cantidad]}#{self[:unidad]}"
27
+ end
28
+
29
+ def to_table
30
+ "| #{self[:nombre]} | #{self[:cantidad]} | #{self[:unidad]} |"
31
+ end
32
+
33
+ def inspect
34
+ to_s
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/bedca_api/constants'
4
+
5
+ module DietaryDsl
6
+ # Clase que representa un tipo de valor nutricional y sus datos
7
+ class FoodValues
8
+ include BEDCA
9
+ include Enumerable
10
+
11
+ def initialize(title, values)
12
+ @title = title
13
+ @data = arr_to_hash(parse_values(values), COMPONENTS) { |value| value[:id] }
14
+ end
15
+
16
+ def [](key)
17
+ @data[key]
18
+ end
19
+
20
+ def each
21
+ @data.each { |i| yield i }
22
+ end
23
+
24
+ def parse_values(values)
25
+ values
26
+ .map { |value| FoodValue.new(value) }
27
+ .uniq { |value| value[:id] }
28
+ end
29
+
30
+ def to_s
31
+ JSON.pretty_generate(@data).gsub(':', ' =>') + "\n"
32
+ end
33
+
34
+ def inspect
35
+ to_s
36
+ end
37
+
38
+ def to_table
39
+ <<~TO_TABLE
40
+ ### #{@title}
41
+
42
+ | Componente | Valor | Unidad |
43
+ |------------|-------|--------|
44
+ #{@data.map { |_key, value| value.to_table }.join("\n")}
45
+ TO_TABLE
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/bedca_api/food'
4
+
5
+ module DietaryDsl
6
+ # Clase que representa un menú. Un menú se compone de distintos platos (entrantes, primeros platos, postres...)
7
+ class Menu
8
+ def initialize(title, &block)
9
+ @title = title
10
+ @platos = []
11
+ instance_eval(&block)
12
+ end
13
+
14
+ def [](key)
15
+ @platos[key]
16
+ end
17
+
18
+ def plato(datos)
19
+ @platos = @platos.push datos
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/bedca_api/food'
4
+
5
+ module DietaryDsl
6
+ # Clase que representa un plato. Un plato es una comida específica, como pulpo a la gallega, o un potaje
7
+ class Plato
8
+ def initialize(title, &block)
9
+ @title = title
10
+ @alimentos = []
11
+ instance_eval(&block)
12
+ end
13
+
14
+ def [](key)
15
+ @alimentos[key]
16
+ end
17
+
18
+ def alimento(datos)
19
+ alimento = DietaryDsl::Food.find_by_like(nombre: datos[:food])
20
+ raise "El alimento #{datos[:food]} no existe" if alimento.nil?
21
+ cantidad = datos[:cantidad]
22
+ @alimentos = @alimentos.push food: alimento, cantidad: cantidad
23
+ end
24
+
25
+ def to_s
26
+ alimentos = @alimentos
27
+ .map { |data| "* #{data[:food][:nombre]}" }
28
+ .join("\n")
29
+
30
+ <<~OUTPUT
31
+ #{@title}
32
+ #{alimentos}
33
+ OUTPUT
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dietary_dsl/measures/measure'
4
+
5
+ module DietaryDsl
6
+ # Esta clase nos permite representar unidades de masa, como gramos o kilogramos.
7
+ class Masa < Measure
8
+ def initialize(en_gramos)
9
+ super(en_gramos)
10
+ end
11
+
12
+ # Métodos de clase para instanciarlo
13
+
14
+ def self.kg(number)
15
+ DietaryDsl::Masa.new(number * 1000)
16
+ end
17
+
18
+ def self.g(number)
19
+ DietaryDsl::Masa.new(number)
20
+ end
21
+
22
+ # Métodos de conversión
23
+
24
+ def g
25
+ @cantidad
26
+ end
27
+
28
+ def gramos
29
+ g
30
+ end
31
+
32
+ def kg
33
+ @cantidad / 1000
34
+ end
35
+
36
+ def kilogramos
37
+ kg
38
+ end
39
+
40
+ # Métodos para multiplicar por un número, p.e. 3 * 10.g
41
+
42
+ def coerce(arg)
43
+ [Masa.new(arg), self]
44
+ end
45
+
46
+ def *(other)
47
+ Masa.new(@cantidad * other.cantidad)
48
+ end
49
+ end
50
+ end
51
+
52
+ # Se expande la clase Numeric con los nuevos métodos para la masa
53
+ class Numeric
54
+ def g
55
+ DietaryDsl::Masa.g(self)
56
+ end
57
+
58
+ def gramo
59
+ g
60
+ end
61
+
62
+ def gramos
63
+ g
64
+ end
65
+
66
+ def kg
67
+ DietaryDsl::Masa.kg(self)
68
+ end
69
+
70
+ def kilogramo
71
+ kg
72
+ end
73
+
74
+ def kilogramos
75
+ kg
76
+ end
77
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DietaryDsl
4
+ # Esta clase nos permite representar unidades de masa, como gramos o kilogramos.
5
+ class Measure
6
+ attr_reader :cantidad
7
+
8
+ def initialize(cantidad)
9
+ @cantidad = cantidad.to_f
10
+ end
11
+
12
+ def to
13
+ self
14
+ end
15
+ end
16
+ end