ingreedyfork 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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