openfoodfacts 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 273c69bba5eca84c0012464a5442bde9793f36ab
4
- data.tar.gz: e70b9511d2bf3ade15e7edf8dcd534d7d68bdee7
3
+ metadata.gz: 09d860eb4659431d4bf589f95572ab8dd0f8fc8d
4
+ data.tar.gz: a23608b0c33c5450db5cacb99b55e9234f1cf96c
5
5
  SHA512:
6
- metadata.gz: 9db37b080d40213333cff30b49a981afa3b40a726f84c68fa45beda509e8a918909344a57538296fe9c879a724b3686047883458fd1e928128020204d2e633ce
7
- data.tar.gz: b4a28ae44b9072407daf43127feb4fc9096fb5e1e7d2e8b763039e54f171c159d05f00226f29593dbc95695ae6e8eab0a363bfafa7703d639b145363f678e430
6
+ metadata.gz: 33fb64a4602691cd37e59d17ad1d659b54888bac32a8ec35307bb324fd61d53964d56c038ff1b748b44e7c0fc3749e8f2d265cef83cf1a74260c06eb036db5a3
7
+ data.tar.gz: 0c3efdae29963a8d5cb8973184bd7ad1c0a9ebdc45078f48b7a0fd0bbb43769be901dd8ee07cb635c84110f264f8077570786664fdad51d78c0b35b96aae3f6b
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # OpenFoodFacts
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/openfoodfacts.svg)](http://badge.fury.io/rb/openfoodfacts)
4
- [![Build Status](https://travis-ci.org/nicolasleger/openfoodfacts-ruby.svg)](https://travis-ci.org/nicolasleger/openfoodfacts-ruby)
4
+ [![Build Status](https://travis-ci.org/openfoodfacts/openfoodfacts-ruby.svg?branch=master)](https://travis-ci.org/openfoodfacts/openfoodfacts-ruby.svg?branch=master)
5
5
  [![Dependency Status](https://gemnasium.com/nicolasleger/openfoodfacts-ruby.svg)](https://gemnasium.com/nicolasleger/openfoodfacts-ruby)
6
6
  [![Code Climate](https://codeclimate.com/github/nicolasleger/openfoodfacts-ruby/badges/gpa.svg)](https://codeclimate.com/github/nicolasleger/openfoodfacts-ruby)
7
7
  [![Coverage Status](https://coveralls.io/repos/nicolasleger/openfoodfacts-ruby/badge.svg)](https://coveralls.io/r/nicolasleger/openfoodfacts-ruby)
@@ -31,8 +31,8 @@ require 'openfoodfacts'
31
31
 
32
32
  # Browse a product
33
33
 
34
- barcode = "3029330003533"
35
- product = Openfoodfacts.product(barcode, locale: 'fr') # or Openfoodfacts::Product.get
34
+ code = "3029330003533"
35
+ product = Openfoodfacts::Product.get(code, locale: 'fr')
36
36
 
37
37
  product.product_name
38
38
  # => "Crousti Moelleux Complet"
@@ -40,6 +40,15 @@ product.product_name
40
40
  product.nutriments.to_hash
41
41
  # => {"sodium"=>"0.44", "sugars"=>6.5, "fat_unit"=>"g", "carbohydrates_unit"=>"g", "proteins_unit"=>"g", "nutrition-score-fr_100g"=>-2, "fat"=>2.5, "proteins_serving"=>12.8, "sodium_serving"=>0.535, "salt"=>1.1176, "proteins"=>10.5, "nutrition-score-uk_serving"=>-2, "nutrition-score-fr"=>-2, "fat_serving"=>3.04, "sugars_unit"=>"g", "sugars_100g"=>"6.5", "sodium_unit"=>"g", "saturated-fat_unit"=>"g", "saturated-fat_serving"=>0.608, "sodium_100g"=>0.44, "fiber_unit"=>"g", "energy"=>1067, "energy_unit"=>"kJ", "sugars_serving"=>7.9, "carbohydrates_100g"=>44, "nutrition-score-uk"=>-2, "proteins_100g"=>10.5, "fiber_serving"=>7.29, "carbohydrates_serving"=>53.5, "nutrition-score-fr_serving"=>-2, "energy_serving"=>1300, "fat_100g"=>"2.5", "saturated-fat_100g"=>"0.5", "nutrition-score-uk_100g"=>-2, "fiber"=>6, "salt_serving"=>1.36, "salt_100g"=>"1.1176", "carbohydrates"=>44, "fiber_100g"=>6, "energy_100g"=>1067, "saturated-fat"=>0.5}
42
42
 
43
+ # Update product
44
+
45
+ user = Openfoodfacts::User.login("USERNAME", "PASSWORD")
46
+ if user
47
+ product.brands = "Jacquet"
48
+ product.update
49
+ # true
50
+ end
51
+
43
52
  # Search products
44
53
 
45
54
  Openfoodfacts::Product.search("Chocolate", locale: 'world', page_size: 3)
@@ -47,7 +56,7 @@ Openfoodfacts::Product.search("Chocolate", locale: 'world', page_size: 3)
47
56
 
48
57
  # Config
49
58
 
50
- Openfoodfacts.locales
59
+ Openfoodfacts:Locale.all
51
60
  # => ["ad", "ad-es", "ad-fr", "ad-pt", "ae", "al", "am", "ar", "at", "au", "ax", "az", "bd", "be", "be-de", "be-fr", "bf", "bg", "bi", "bi-rn", "bn", "br", "by", "by-be", "bz", "ca", "ca-fr", "cg", "ch", "ch-fr", "ch-it", "ci", "cl", "cn", "co", "cr", "cu", "cy", "cy-tr", "cz", "de", "dk", "do", "dz", "dz-fr", "ec", "eg", "es", "es-ca", "es-eu", "es-gl", "fi", "fi-sv", "fr", "ga", "gf", "gn", "gp", "gr", "hk", "hr", "hu", "id", "ie", "ie-ga", "il", "il-ar", "il-ru", "in", "iq", "iq-ku", "ir", "is", "it", "jp", "ke", "ke-sw", "kh", "kr", "kw", "kz", "kz-kk", "lb", "lk", "lk-ta", "lu", "lu-de", "lu-lb", "lv", "ma", "ma-es", "ma-fr", "mc", "md", "mf", "ml", "mn", "mo", "mo-zh", "mq", "mr", "mt", "mt-mt", "mu", "mx", "my", "nc", "nl", "no", "nz", "nz-mi", "pa", "pe", "pf", "ph", "ph-tl", "pl", "pm", "pt", "qa", "re", "ro", "rs", "ru", "sa", "se", "sg", "sg-ms", "sg-ta", "sg-zh", "si", "sk", "sn", "sy", "th", "tn", "tr", "tw", "tz", "tz-sw", "ua", "uk", "us", "ve", "vn", "vu", "vu-bi", "world", "ye", "yt", "za", "za-af", "za-nr", "za-ss", "za-st", "za-tn", "za-ts", "za-ve", "za-xh", "za-zu"]
52
61
  ```
53
62
 
@@ -1,4 +1,6 @@
1
+ require_relative 'openfoodfacts/locale'
1
2
  require_relative 'openfoodfacts/product'
3
+ require_relative 'openfoodfacts/user'
2
4
  require_relative 'openfoodfacts/version'
3
5
 
4
6
  require 'json'
@@ -6,26 +8,21 @@ require 'nokogiri'
6
8
  require 'open-uri'
7
9
 
8
10
  module Openfoodfacts
9
- DEFAULT_LOCALE = 'world'
11
+
12
+ DEFAULT_LOCALE = Locale::GLOBAL
10
13
 
11
14
  class << self
12
15
 
13
16
  # Return locale from link
14
17
  #
15
18
  def locale_from_link(link)
16
- link[/^https?:\/\/([^.]+)\./i, 1]
19
+ Locale.locale_from_link(link)
17
20
  end
18
21
 
19
22
  # Get locales
20
23
  #
21
24
  def locales
22
- url = "http://openfoodfacts.org/"
23
- body = open(url).read
24
- dom = Nokogiri.parse(body)
25
-
26
- dom.css('ul li a').map { |locale_link|
27
- locale_from_link(locale_link.attr('href'))
28
- }.uniq.sort
25
+ Locale.all
29
26
  end
30
27
 
31
28
  # Get product
@@ -0,0 +1,29 @@
1
+ module Openfoodfacts
2
+ class Locale < String
3
+
4
+ GLOBAL = 'world'
5
+
6
+ class << self
7
+
8
+ # Get locales
9
+ #
10
+ def all
11
+ url = "http://openfoodfacts.org/"
12
+ body = open(url).read
13
+ dom = Nokogiri.parse(body)
14
+
15
+ dom.css('ul li a').map { |locale_link|
16
+ locale_from_link(locale_link.attr('href'))
17
+ }.uniq.sort
18
+ end
19
+
20
+ # Return locale from link
21
+ #
22
+ def locale_from_link(link)
23
+ link[/^https?:\/\/([^.]+)\./i, 1]
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -1,25 +1,29 @@
1
1
  require 'hashie'
2
- require 'json'
3
2
  require 'nokogiri'
4
3
  require 'open-uri'
5
4
 
6
5
  module Openfoodfacts
7
6
  class Product < Hashie::Mash
7
+
8
8
  class << self
9
+
9
10
  # Get product
10
11
  #
11
- def get(barcode, locale: Openfoodfacts::DEFAULT_LOCALE)
12
- product_url = url(barcode, locale: locale)
13
- json = open(product_url).read
14
- hash = JSON.parse(json)
12
+ def get(code, locale: Openfoodfacts::DEFAULT_LOCALE)
13
+ if code
14
+ product_url = url(code, locale: locale)
15
+ json = open(product_url).read
16
+ hash = JSON.parse(json)
15
17
 
16
- new(hash["product"]) if !hash["status"].nil? && hash["status"] == 1
18
+ new(hash["product"]) if !hash["status"].nil? && hash["status"] == 1
19
+ end
17
20
  end
21
+ alias_method :find, :get
18
22
 
19
23
  # Return product API URL
20
24
  #
21
- def url(barcode, locale: Openfoodfacts::DEFAULT_LOCALE)
22
- "http://#{locale}.openfoodfacts.org/api/v0/produit/#{barcode}.json"
25
+ def url(code, locale: Openfoodfacts::DEFAULT_LOCALE)
26
+ "http://#{locale}.openfoodfacts.org/api/v0/produit/#{code}.json"
23
27
  end
24
28
 
25
29
  # Search products
@@ -52,6 +56,47 @@ module Openfoodfacts
52
56
  new(attributes)
53
57
  end
54
58
  end
59
+ alias_method :where, :search
60
+
61
+ end
62
+
63
+ # Fetch product
64
+ #
65
+ def fetch
66
+ if (self.code)
67
+ product = self.class.get(self.code)
68
+ self.merge!(product)
69
+ end
70
+
71
+ self
72
+ end
73
+ alias_method :reload, :fetch
74
+
75
+ # Update product
76
+ # Only product_name, brands and quantity fields seems to be updatable throught app / API.
77
+ # User can be nil
78
+ # Tested not updatable fields: countries, ingredients_text, purchase_places, purchase_places_tag, purchase_places_tags
79
+ #
80
+ def update(user: nil)
81
+ if self.code && self.lc
82
+ uri = URI("http://#{self.lc}.openfoodfacts.org/cgi/product_jqm.pl")
83
+ params = self.to_hash
84
+ params.merge!("user_id" => user.user_id, "password" => user.password) if user
85
+ response = Net::HTTP.post_form(uri, params)
86
+
87
+ data = JSON.parse(response.body)
88
+ data["status"] == 1
89
+ else
90
+ false
91
+ end
92
+ end
93
+ alias_method :save, :update
94
+
95
+ # Return Product API URL
96
+ #
97
+ def url(locale: Openfoodfacts::DEFAULT_LOCALE)
98
+ self.class.url(self.code, locale: locale)
55
99
  end
100
+
56
101
  end
57
102
  end
@@ -0,0 +1,38 @@
1
+ module Openfoodfacts
2
+ class User < Hashie::Mash
3
+
4
+ class << self
5
+
6
+ # Login
7
+ # WARNING SECURITY: It is not made throught HTTPS Secure so password can be read on the way.
8
+ #
9
+ def login(user_id, password, locale: Openfoodfacts::DEFAULT_LOCALE)
10
+ uri = URI("http://#{locale}.openfoodfacts.org/cgi/session.pl")
11
+ params = {
12
+ "jqm" => "1",
13
+ "user_id" => user_id,
14
+ "password" => password
15
+ }
16
+
17
+ response = Net::HTTP.post_form(uri, params)
18
+ data = JSON.parse(response.body)
19
+
20
+ if data['user_id']
21
+ data.merge!(password: password)
22
+ new(data)
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ # Login
29
+ #
30
+ def login(locale: Openfoodfacts::DEFAULT_LOCALE)
31
+ if user = self.class.login(self.user_id, self.password, locale: locale)
32
+ self.name = user.name
33
+ self
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module Openfoodfacts
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,28 +1,56 @@
1
1
  require_relative 'minitest_helper'
2
2
 
3
3
  class TestOpenfoodfacts < Minitest::Test
4
+
5
+ # Gem
6
+
4
7
  def test_that_it_has_a_version_number
5
8
  refute_nil ::Openfoodfacts::VERSION
6
9
  end
7
10
 
11
+ # Locale
12
+
8
13
  def test_it_fetches_locales
9
14
  VCR.use_cassette("index") do
10
- locales = ::Openfoodfacts::locales
15
+ locales = ::Openfoodfacts::Locale.all
11
16
  assert_includes locales, "world"
12
17
  assert_includes locales, "fr"
13
18
  assert_includes locales, "be-fr"
14
19
  end
15
20
  end
16
21
 
22
+ # User
23
+
24
+ def test_it_login_user
25
+ VCR.use_cassette("login_user", record: :once, match_requests_on: [:host, :path]) do
26
+ user = ::Openfoodfacts::User.login("wrong", "absolutely")
27
+ assert_nil user
28
+ end
29
+ end
30
+
31
+ # Product
32
+
33
+ def test_it_returns_product_url
34
+ product = ::Openfoodfacts::Product.new(code: "3029330003533")
35
+ assert_equal ::Openfoodfacts::Product.url(product.code, locale: 'ca'), product.url(locale: 'ca')
36
+ end
37
+
17
38
  def test_it_fetches_product
18
39
  product_code = "3029330003533"
40
+
41
+ VCR.use_cassette("fetch_product_#{product_code}", record: :once, match_requests_on: [:host, :path]) do
42
+ product = ::Openfoodfacts::Product.new(code: product_code)
43
+ product.fetch
44
+ refute_empty product.brands_tags
45
+ end
46
+ end
47
+
48
+ def test_it_get_product
49
+ product_code = "3029330003533"
19
50
 
20
51
  VCR.use_cassette("product_#{product_code}", record: :once, match_requests_on: [:host, :path]) do
21
52
  assert_equal ::Openfoodfacts::Product.get(product_code).code, product_code
22
53
  end
23
- VCR.use_cassette("product_#{product_code}", record: :once, match_requests_on: [:host, :path]) do
24
- #assert_equal ::Openfoodfacts.product(product_code).code, product_code # Backward compatibility
25
- end
26
54
  end
27
55
 
28
56
  def test_that_it_search
@@ -42,4 +70,26 @@ class TestOpenfoodfacts < Minitest::Test
42
70
  refute_equal ::Openfoodfacts::Product.search(term, page: 2).first.code, first_product.code
43
71
  end
44
72
  end
73
+
74
+ def test_it_updates_product
75
+ product_code = "3029330003533"
76
+ product = ::Openfoodfacts::Product.new(code: product_code)
77
+ product_last_modified_t = nil
78
+
79
+ VCR.use_cassette("fetch_product_#{product_code}", record: :all, match_requests_on: [:host, :path]) do
80
+ product.fetch
81
+ product_last_modified_t = product.last_modified_t
82
+ end
83
+
84
+ VCR.use_cassette("update_product_#{product_code}", record: :all, match_requests_on: [:host, :path]) do
85
+ product.update # Empty update are accepted, allow testing without altering data.
86
+ end
87
+
88
+ VCR.use_cassette("refetch_product_#{product_code}", record: :all, match_requests_on: [:host, :path]) do
89
+ product.fetch
90
+ end
91
+
92
+ refute_equal product_last_modified_t, product.last_modified_t
93
+ end
94
+
45
95
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openfoodfacts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Leger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-21 00:00:00.000000000 Z
11
+ date: 2015-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -119,7 +119,9 @@ files:
119
119
  - README.md
120
120
  - Rakefile
121
121
  - lib/openfoodfacts.rb
122
+ - lib/openfoodfacts/locale.rb
122
123
  - lib/openfoodfacts/product.rb
124
+ - lib/openfoodfacts/user.rb
123
125
  - lib/openfoodfacts/version.rb
124
126
  - test/fixtures/index.yml
125
127
  - test/fixtures/product_3029330003533.yml