ingreedyfork 0.1.10

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,56 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Ingreedy::Rationalizer do
5
+ subject { described_class }
6
+
7
+ context "with an integer and a fraction" do
8
+ it "gives back an improper rational" do
9
+ rational = subject.rationalize(integer: "1", fraction: "1/2")
10
+ expect(rational).to eq("3/2".to_r)
11
+ end
12
+ end
13
+
14
+ context "with a fraction" do
15
+ it "gives back a rational" do
16
+ expect(subject.rationalize(fraction: "1/2")).to eq("1/2".to_r)
17
+ end
18
+ end
19
+
20
+ context "with a vulgar fraction" do
21
+ it "gives back a rational" do
22
+ expect(subject.rationalize(fraction: "¼")).to eq("1/4".to_r)
23
+ end
24
+ end
25
+
26
+ context "with an integer" do
27
+ it "gives back a rational" do
28
+ expect(subject.rationalize(integer: "2")).to eq("2".to_r)
29
+ end
30
+ end
31
+
32
+ context "with a float" do
33
+ it "gives back a rational" do
34
+ expect(subject.rationalize(float: "0.3")).to eq("3/10".to_r)
35
+ end
36
+ end
37
+
38
+ context "with a european float" do
39
+ it "gives back a rational" do
40
+ expect(subject.rationalize(float: "0,4")).to eq("4/10".to_r)
41
+ end
42
+ end
43
+
44
+ context "with an english digit" do
45
+ it "gives back a rational" do
46
+ expect(subject.rationalize(word: "one")).to eq("1".to_r)
47
+ end
48
+ end
49
+
50
+ context "with the word a or an" do
51
+ it "gives back a rational" do
52
+ expect(subject.rationalize(word: "a")).to eq("1".to_r)
53
+ expect(subject.rationalize(word: "AN")).to eq("1".to_r)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Ingreedy::UnitVariationMapper do
4
+ subject { described_class }
5
+
6
+ describe ".unit_from_variation" do
7
+ context "uppercased variation" do
8
+ it "gives back the correct unit as a symbol" do
9
+ expect(subject.unit_from_variation("TSP")).to eq(:teaspoon)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,508 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Ingreedy, ".parse" do
5
+ it "parses a simple example correctly" do
6
+ result = Ingreedy.parse("1 lb potatoes")
7
+
8
+ expect(result.amount).to eq(1)
9
+ expect(result.unit).to eq(:pound)
10
+ expect(result.ingredient).to eq("potatoes")
11
+ end
12
+ end
13
+
14
+ describe Ingreedy, "amount parsing" do
15
+ {
16
+ "1 cup flour" => 1,
17
+ "one cup flour" => 1,
18
+ "1 1/2 cups flour" => "3/2",
19
+ "¼ cups flour" => "1/4",
20
+ "1 ½ cups flour" => "3/2",
21
+ "1½ cups flour" => "3/2",
22
+ "1.0 cup flour" => 1,
23
+ "1.5 cups flour" => "3/2",
24
+ "1,5 cups flour" => "3/2",
25
+ "1 2/3 cups flour" => "5/3",
26
+ "1 (28 ounce) can crushed tomatoes" => 1,
27
+ "2 (28 ounce) can crushed tomatoes" => 2,
28
+ "3 28 ounce can crushed tomatoes" => 3,
29
+ "one 28 ounce can crushed tomatoes" => 1,
30
+ "two five-ounce can crushed tomatoes" => 2,
31
+ "two 28 ounce cans crushed tomatoes" => 2,
32
+ "three 28 ounce cans crushed tomatoes" => 3,
33
+ "1/2 cups flour" => "1/2",
34
+ ".25 cups flour" => "1/4",
35
+ "12oz tequila" => 12,
36
+ "1 banana" => 1,
37
+ }.each do |query, expected|
38
+ it "parses the correct amount as a rational" do
39
+ expect(Ingreedy.parse(query)).to parse_the_amount(expected.to_r)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe Ingreedy, "amount parsing preserving original value" do
45
+ around do |example|
46
+ Ingreedy.preserve_amounts = true
47
+ example.run
48
+ Ingreedy.preserve_amounts = false
49
+ end
50
+
51
+ {
52
+ "1 cup flour" => "1",
53
+ "2 cups flour" => "2",
54
+ "1 1/2 cups flour" => "1 1/2",
55
+ "¼ cups flour" => "1/4",
56
+ "1 ½ cups flour" => "1 1/2",
57
+ "1½ cups flour" => "1 1/2",
58
+ "1.0 cup flour" => "1.0",
59
+ "1.5 cups flour" => "1.5",
60
+ "1,5 cups flour" => "1,5",
61
+ "1/2 cups flour" => "1/2",
62
+ ".25 cups flour" => ".25",
63
+ }.each do |query, expected|
64
+ it "parses the correct amount" do
65
+ expect(Ingreedy.parse(query).amount).to eq(expected)
66
+ end
67
+ end
68
+ end
69
+
70
+ describe Ingreedy, "english units" do
71
+ context "abbreviated" do
72
+ {
73
+ "1 c flour" => :cup,
74
+ "1 c. flour" => :cup,
75
+ "1 fl oz flour" => :fluid_ounce,
76
+ "1 fl. oz. flour" => :fluid_ounce,
77
+ "2 gal flour" => :gallon,
78
+ "2 gal. flour" => :gallon,
79
+ "1 ounce flour" => :ounce,
80
+ "2 ounces flour" => :ounce,
81
+ "1 oz flour" => :ounce,
82
+ "1 oz. flour" => :ounce,
83
+ "2 pt flour" => :pint,
84
+ "2 pt. flour" => :pint,
85
+ "1 lb flour" => :pound,
86
+ "1 lb. flour" => :pound,
87
+ "1 pound flour" => :pound,
88
+ "2 pounds flour" => :pound,
89
+ "2 qt flour" => :quart,
90
+ "2 qt. flour" => :quart,
91
+ "2 qts flour" => :quart,
92
+ "2 qts. flour" => :quart,
93
+ "2 tbsp flour" => :tablespoon,
94
+ "2 tbsp. flour" => :tablespoon,
95
+ "2 Tbs flour" => :tablespoon,
96
+ "2 Tbs. flour" => :tablespoon,
97
+ "2 T flour" => :tablespoon,
98
+ "2 T. flour" => :tablespoon,
99
+ "2 tsp flour" => :teaspoon,
100
+ "2 tsp. flour" => :teaspoon,
101
+ "2 t flour" => :teaspoon,
102
+ "2 t. flour" => :teaspoon,
103
+ "12oz tequila" => :ounce,
104
+ "2 TSP flour" => :teaspoon,
105
+ "1 LB flour" => :pound,
106
+ "1 tSP sugar" => :teaspoon,
107
+ }.each do |query, expected|
108
+ it "parses the #{expected} unit correctly" do
109
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
110
+ end
111
+ end
112
+ end
113
+
114
+ context "long form" do
115
+ {
116
+ "1 cup flour" => :cup,
117
+ "2 cups flour" => :cup,
118
+ "1 fluid ounce flour" => :fluid_ounce,
119
+ "2 fluid ounces flour" => :fluid_ounce,
120
+ "2 gallon flour" => :gallon,
121
+ "2 gallons flour" => :gallon,
122
+ "2 pint flour" => :pint,
123
+ "2 pints flour" => :pint,
124
+ "1 quart flour" => :quart,
125
+ "2 quarts flour" => :quart,
126
+ "2 tablespoon flour" => :tablespoon,
127
+ "2 tablespoons flour" => :tablespoon,
128
+ "2 teaspoon flour" => :teaspoon,
129
+ "2 teaspoons flour" => :teaspoon,
130
+ }.each do |query, expected|
131
+ it "parses the units correctly" do
132
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ describe Ingreedy, "metric units" do
139
+ context "abbreviated" do
140
+ {
141
+ "1 g flour" => :gram,
142
+ "1 g. flour" => :gram,
143
+ "1 gr flour" => :gram,
144
+ "1 gr. flour" => :gram,
145
+ "1 kg flour" => :kilogram,
146
+ "1 kg. flour" => :kilogram,
147
+ "1 l water" => :liter,
148
+ "1 l. water" => :liter,
149
+ "1 mg water" => :milligram,
150
+ "1 mg. water" => :milligram,
151
+ "1 ml water" => :milliliter,
152
+ "1 ml. water" => :milliliter,
153
+ }.each do |query, expected|
154
+ it "parses the units correctly" do
155
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
156
+ end
157
+ end
158
+ end
159
+
160
+ context "long form" do
161
+ {
162
+ "1 gram flour" => :gram,
163
+ "2 grams flour" => :gram,
164
+ "1 kilogram flour" => :kilogram,
165
+ "2 kilograms flour" => :kilogram,
166
+ "1 liter water" => :liter,
167
+ "2 liters water" => :liter,
168
+ "1 milligram water" => :milligram,
169
+ "2 milligrams water" => :milligram,
170
+ "1 milliliter water" => :milliliter,
171
+ "2 milliliters water" => :milliliter,
172
+ }.each do |query, expected|
173
+ it "parses the units correctly" do
174
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ describe Ingreedy, "nonstandard units" do
181
+ {
182
+ "1 pinch pepper" => :pinch,
183
+ "2 pinches pepper" => :pinch,
184
+ "1 dash salt" => :dash,
185
+ "2 dashes salt" => :dash,
186
+ "1 touch hot sauce" => :touch,
187
+ "2 touches hot sauce" => :touch,
188
+ "1 handful rice" => :handful,
189
+ "2 handfuls rice" => :handful,
190
+ "1 stick of butter" => :stick,
191
+ "2 cloves of garlic" => :clove,
192
+ "1 can of tomatoes" => :can,
193
+ }.each do |query, expected|
194
+ it "parses the units correctly" do
195
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
196
+ end
197
+ end
198
+ end
199
+
200
+ describe Ingreedy, "without units" do
201
+ it "parses correctly" do
202
+ result = Ingreedy.parse "3 eggs, lightly beaten"
203
+
204
+ expect(result.amount).to eq(3)
205
+ expect(result.unit).to be_nil
206
+ expect(result.ingredient).to eq("eggs, lightly beaten")
207
+ end
208
+ end
209
+
210
+ describe Ingreedy, "container as part of quantity" do
211
+ it "parses correctly" do
212
+ result = Ingreedy.parse "160g (2 cans) of tomatoes"
213
+
214
+ expect(result.amount).to eq(160)
215
+ expect(result.unit).to eq(:gram)
216
+ expect(result.container_amount).to eq(2)
217
+ expect(result.container_unit).to eq(:can)
218
+ expect(result.ingredient).to eq("tomatoes")
219
+ end
220
+
221
+ context "on language without preposition" do
222
+ before(:all) do
223
+ Ingreedy.dictionaries[:id] = {
224
+ units: {
225
+ can: ["kaleng"],
226
+ gram: ["g"],
227
+ to_taste: ["secukupnya"],
228
+ },
229
+ }
230
+ Ingreedy.locale = :id
231
+ end
232
+
233
+ after(:all) do
234
+ Ingreedy.locale = nil
235
+ end
236
+
237
+ it "parses correctly" do
238
+ result = Ingreedy.parse "160g (2 kaleng) tomat"
239
+
240
+ expect(result.amount).to eq(160)
241
+ expect(result.unit).to eq(:gram)
242
+ expect(result.container_amount).to eq(2)
243
+ expect(result.container_unit).to eq(:can)
244
+ expect(result.ingredient).to eq("tomat")
245
+ end
246
+ end
247
+ end
248
+
249
+ describe Ingreedy, "with 'a' as quantity and preposition 'of'" do
250
+ it "parses correctly" do
251
+ result = Ingreedy.parse "a dash of ginger"
252
+
253
+ expect(result.amount).to eq(1)
254
+ expect(result.unit).to eq(:dash)
255
+ expect(result.ingredient).to eq("ginger")
256
+ end
257
+ end
258
+
259
+ describe Ingreedy, "with 'reverse format'" do
260
+ it "works with words containing a 'word digit'" do
261
+ result = Ingreedy.parse "salt 200g"
262
+
263
+ expect(result.amount).to eq(200)
264
+ expect(result.unit).to eq(:gram)
265
+ expect(result.ingredient).to eq("salt")
266
+ end
267
+
268
+ it "works with words ending on a 'word digit'" do
269
+ result = Ingreedy.parse "quinoa 200g"
270
+
271
+ expect(result.amount).to eq(200)
272
+ expect(result.unit).to eq(:gram)
273
+ expect(result.ingredient).to eq("quinoa")
274
+ end
275
+
276
+ it "works with approximate quantities" do
277
+ result = Ingreedy.parse "salt to taste"
278
+
279
+ expect(result.ingredient).to eq("salt")
280
+ expect(result.amount).to be_nil
281
+ expect(result.unit).to eq(:to_taste)
282
+ end
283
+ end
284
+
285
+ describe Ingreedy, "Given a range" do
286
+ it "works with simple ranges" do
287
+ result = Ingreedy.parse "1-2 tbsp salt"
288
+
289
+ expect(result.amount).to eq([1, 2])
290
+ expect(result.unit).to eq(:tablespoon)
291
+ expect(result.ingredient).to eq("salt")
292
+ end
293
+
294
+ it "works with spaces" do
295
+ result = Ingreedy.parse "1 - 2 tbsp salt"
296
+
297
+ expect(result.amount).to eq([1, 2])
298
+ expect(result.unit).to eq(:tablespoon)
299
+ expect(result.ingredient).to eq("salt")
300
+ end
301
+
302
+ it "works with tilde" do
303
+ result = Ingreedy.parse "1~2 tbsp salt"
304
+
305
+ expect(result.amount).to eq([1, 2])
306
+ expect(result.unit).to eq(:tablespoon)
307
+ expect(result.ingredient).to eq("salt")
308
+ end
309
+ end
310
+
311
+ describe Ingreedy, "parsing in language with no prepositions" do
312
+ before(:all) do
313
+ Ingreedy.dictionaries[:id] = {
314
+ units: {
315
+ gram: ["g"],
316
+ to_taste: ["secukupnya"],
317
+ },
318
+ }
319
+ Ingreedy.locale = :id
320
+ end
321
+
322
+ after(:all) do
323
+ Ingreedy.locale = nil
324
+ end
325
+
326
+ it "parses correctly" do
327
+ result = Ingreedy.parse "garam secukupnya"
328
+
329
+ expect(result.amount).to be_nil
330
+ expect(result.unit).to eq(:to_taste)
331
+ expect(result.ingredient).to eq("garam")
332
+ end
333
+ end
334
+
335
+ describe Ingreedy, "custom dictionaries" do
336
+ context "using Ingreedy.locale=" do
337
+ before(:all) do
338
+ Ingreedy.dictionaries[:fr] = {
339
+ numbers: { "une" => 1 },
340
+ prepositions: ["de"],
341
+ units: { dash: ["pincee"] },
342
+ }
343
+ Ingreedy.locale = :fr
344
+ end
345
+
346
+ after(:all) do
347
+ Ingreedy.locale = nil
348
+ end
349
+
350
+ it "parses correctly" do
351
+ result = Ingreedy.parse "une pincee de sucre"
352
+
353
+ expect(result.amount).to eq(1)
354
+ expect(result.unit).to eq(:dash)
355
+ expect(result.ingredient).to eq("sucre")
356
+ end
357
+ end
358
+
359
+ context "using I18n.locale" do
360
+ before(:each) do
361
+ Ingreedy.dictionaries[:de] = { units: { dash: ["prise"] } }
362
+ stub_const "I18n", double("I18n", locale: :de)
363
+ end
364
+
365
+ it "parses correctly" do
366
+ result = Ingreedy.parse "1 Prise Zucker"
367
+
368
+ expect(result.amount).to eq(1)
369
+ expect(result.unit).to eq(:dash)
370
+ expect(result.ingredient).to eq("Zucker")
371
+ end
372
+ end
373
+
374
+ context "unknown locale" do
375
+ before(:all) do
376
+ Ingreedy.locale = :da
377
+ end
378
+
379
+ after(:all) do
380
+ Ingreedy.locale = nil
381
+ end
382
+
383
+ it "raises an informative exception" do
384
+ expect do
385
+ Ingreedy.parse "1 tsk salt"
386
+ end.to raise_exception("No dictionary found for :da locale")
387
+ end
388
+ end
389
+
390
+ context "Dictionary with no units" do
391
+ it "raises an informative exception" do
392
+ expect do
393
+ Ingreedy.dictionaries[:da] = {}
394
+ end.to raise_exception("No units found in dictionary")
395
+ end
396
+ end
397
+ end
398
+
399
+ describe Ingreedy, "ingredient formatting" do
400
+ it "strips preceding or trailing whitespace" do
401
+ expect(Ingreedy.parse("1 cup flour ").ingredient).to eq("flour")
402
+ end
403
+ end
404
+
405
+ describe Ingreedy, "unit parsing with :pl locale" do
406
+ context "Polish locale" do
407
+ before(:all) do
408
+ Ingreedy.locale = :pl
409
+ end
410
+
411
+ after(:all) do
412
+ Ingreedy.locale = nil
413
+ end
414
+ {
415
+ "1 szklanka mąki" => :cup,
416
+ "2 łyżki mąki" => :spoon,
417
+ "1 łyżka mąki" => :spoon,
418
+ "1 płaska łyżka mąki" => :spoon,
419
+ }.each do |query, expected|
420
+ it "parses the #{expected} unit correctly" do
421
+ expect(Ingreedy.parse(query)).to parse_the_unit(expected)
422
+ end
423
+ end
424
+ end
425
+ end
426
+
427
+ describe Ingreedy, "without units" do
428
+ context "Polish locale" do
429
+ before(:all) do
430
+ Ingreedy.locale = :pl
431
+ end
432
+
433
+ after(:all) do
434
+ Ingreedy.locale = nil
435
+ end
436
+ it "parses correctly units that is prefix of other unit" do
437
+ result = Ingreedy.parse "3 płaskie łyżki majonezu"
438
+
439
+ expect(result.amount).to eq(3)
440
+ expect(result.unit).to eq :spoon
441
+ expect(result.ingredient).to eq("majonezu")
442
+ end
443
+ end
444
+ end
445
+
446
+ describe Ingreedy, "amount parsing with :pl locale" do
447
+ context "Polish locale" do
448
+ before(:all) do
449
+ Ingreedy.locale = :pl
450
+ end
451
+
452
+ after(:all) do
453
+ Ingreedy.locale = nil
454
+ end
455
+ {
456
+ "2x ziemniak" => 2,
457
+ "ziemniak 2x" => 2,
458
+ "1 szklanka mąki" => 1,
459
+ "jedna szklanka mąki" => 1,
460
+ "półtora szklanki mąki" => 1.5,
461
+ "1.5 szklanki mąki" => 1.5,
462
+ "1 1/2 szklanki mąki" => "3/2",
463
+ "¼ szklanki mąki" => "1/4",
464
+ "1 ½ szklanki mąki" => "3/2",
465
+ "1½ szklanki mąki" => "3/2",
466
+ "1.0 szklanka mąki" => 1,
467
+ "1,5 szklanki mąki" => "3/2",
468
+ "1 2/3 szklanki mąki" => "5/3",
469
+ "1 (400g) puszka zmiksowanych pomidorów" => 1,
470
+ "2 (400g) puszki zmiksowanych pomidorów" => 2,
471
+ "3 400 gramowe puszki zmiksowanych pomidorów" => 3,
472
+ "jedna 400 gramowa puszka zmiksowanych pomidorów" => 1,
473
+ "dwie czterysta gramowe puszki zmiksowanych pomidorów" => 2,
474
+ "dwie 400 gramowe puszki zmiksowanych pomidorów" => 2,
475
+ "trzy 400 gramowe puszki zmiksowanych pomidorów" => 3,
476
+ "1/2 szklanki mąki" => "1/2",
477
+ ".25 szklanki mąki" => "1/4",
478
+ "12l tequili" => 12,
479
+ "1 banan" => 1,
480
+ "marchewka 3x" => 3,
481
+ "x3 marchewka" => 3,
482
+ "marchewka x3" => 3,
483
+ "marchewki trzy" => 3,
484
+ }.each do |query, expected|
485
+ it "parses the correct amount as a rational" do
486
+ parsed = nil
487
+ begin
488
+ parsed = Ingreedy.parse(query)
489
+ rescue => e
490
+ puts "failed on #{query} with #{e.class}"
491
+ #puts e
492
+ #puts e.class
493
+ #necessary as raising e crashes rspec - for further investigation try to run parsing test on something like "banana"
494
+ # report on https://github.com/rspec/rspec-core/issues?page=2&q=is%3Aissue+is%3Aopen
495
+ end
496
+ expect(parsed).to parse_the_amount(expected.to_r)
497
+ end
498
+ end
499
+ end
500
+ end
501
+
502
+ describe Ingreedy, "error handling" do
503
+ it "wraps Parslet exceptions in a custom exception" do
504
+ expect do
505
+ Ingreedy.parse("nonsense")
506
+ end.to raise_error Ingreedy::ParseFailed
507
+ end
508
+ end