Class: Openbeautyfacts::Product

Inherits:
Hashie::Mash
  • Object
show all
Defined in:
lib/openbeautyfacts/product.rb

Constant Summary collapse

LOCALE_WEBURL_PREFIXES =

TODO: Add more locales

{
  'fr' => 'produit',
  'uk' => 'product',
  'us' => 'product',
  'world' => 'product'
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.from_html_list(html, list_css_selector, code_from_link_regex, locale: 'world') ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/openbeautyfacts/product.rb', line 55

def from_html_list(html, list_css_selector, code_from_link_regex, locale: 'world')
  dom = Nokogiri::HTML.fragment(html)
  dom.css(list_css_selector).map do |product|
    attributes = {}

    if link = product.css('a').first
      attributes["product_name"] = link.inner_text.strip

      if code = link.attr('href')[code_from_link_regex, 1]
        attributes["_id"] = code
        attributes["code"] = code
      end
    end

    if image = product.css('img').first and image_url = image.attr('src')
      attributes["image_small_url"] = image_url
      attributes["lc"] = Locale.locale_from_link(image_url)
    end
    attributes["lc"] ||= locale

    new(attributes)
  end

end

.from_jquery_mobile_list(jqm_html) ⇒ Object



80
81
82
# File 'lib/openbeautyfacts/product.rb', line 80

def from_jquery_mobile_list(jqm_html)
  from_html_list(jqm_html, 'ul li:not(#loadmore)', /code=(\d+)\Z/i)
end

.from_website_list(html, locale: 'world') ⇒ Object



84
85
86
# File 'lib/openbeautyfacts/product.rb', line 84

def from_website_list(html, locale: 'world')
  from_html_list(html, 'ul.products li', /\/(\d+)\/?/i, locale: 'world')
end

.from_website_page(page_url, page: -1,, products_count: nil) ⇒ Object

page -1 to fetch all pages



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/openbeautyfacts/product.rb', line 89

def from_website_page(page_url, page: -1, products_count: nil)
  if page == -1
    if products_count # Avoid one call
      pages_count = (products_count.to_f / 20).ceil
      (1..pages_count).map { |page| from_website_page(page_url, page: page) }.flatten
    else
      products = []

      page = 1
      begin
        products_on_page = from_website_page(page_url, page: page)
        products += products_on_page
        page += 1
      end while products_on_page.any?

      products
    end
  else
    html = open("#{page_url}/#{page}").read
    from_website_list(html, locale: Locale.locale_from_link(page_url))
  end
end

.get(code, locale: DEFAULT_LOCALE) ⇒ Object Also known as: find

Get product



21
22
23
24
25
26
27
28
29
# File 'lib/openbeautyfacts/product.rb', line 21

def get(code, locale: DEFAULT_LOCALE)
  if code
    product_url = url(code, locale: locale)
    json = open(product_url).read
    hash = JSON.parse(json)

    new(hash["product"]) if !hash["status"].nil? && hash["status"] == 1
  end
end

.search(terms, locale: DEFAULT_LOCALE, page: 1, page_size: 20, sort_by: 'unique_scans_n', domain: DEFAULT_DOMAIN) ⇒ Object Also known as: where

Search products



43
44
45
46
47
48
49
50
51
52
# File 'lib/openbeautyfacts/product.rb', line 43

def search(terms, locale: DEFAULT_LOCALE, page: 1, page_size: 20, sort_by: 'unique_scans_n', domain: DEFAULT_DOMAIN)
  terms = CGI.escape(terms)
  path = "cgi/search.pl?search_terms=#{terms}&jqm=1&page=#{page}&page_size=#{page_size}&sort_by=#{sort_by}"
  url = "https://#{locale}.#{domain}/#{path}"
  json = open(url).read
  hash = JSON.parse(json)
  html = hash["jqm"]

  from_jquery_mobile_list(html)
end

.tags_from_page(_klass, page_url, &custom_tag_parsing) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/openbeautyfacts/product.rb', line 112

def tags_from_page(_klass, page_url, &custom_tag_parsing)
  html = open(page_url).read
  dom = Nokogiri::HTML.fragment(html)

  dom.css('table#tagstable tbody tr').map do |tag|
    if custom_tag_parsing
      custom_tag_parsing.call(tag)
    else
      link = tag.css('a').first

      _klass.new({
        "name" => link.text.strip,
        "url" => URI.join(page_url, link.attr('href')).to_s,
        "products_count" => tag.css('td')[1].text.to_i
      })
    end
  end
end

.url(code, locale: DEFAULT_LOCALE, domain: DEFAULT_DOMAIN) ⇒ Object

Return product API URL



34
35
36
37
38
39
# File 'lib/openbeautyfacts/product.rb', line 34

def url(code, locale: DEFAULT_LOCALE, domain: DEFAULT_DOMAIN)
  if code
    path = "api/v0/produit/#{code}.json"
    "https://#{locale}.#{domain}/#{path}"
  end
end

Instance Method Details

#fetchObject Also known as: reload

Fetch product



135
136
137
138
139
140
141
142
# File 'lib/openbeautyfacts/product.rb', line 135

def fetch
  if (self.code)
    product = self.class.get(self.code)
    self.merge!(product)
  end

  self
end

#update(user: nil, domain: DEFAULT_DOMAIN) ⇒ Object Also known as: save

Update product Only product_name, brands and quantity fields seems to be updatable throught app / API. User can be nil Tested not updatable fields: countries, ingredients_text, purchase_places, purchase_places_tag, purchase_places_tags



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/openbeautyfacts/product.rb', line 150

def update(user: nil, domain: DEFAULT_DOMAIN)
  if self.code && self.lc
    subdomain = self.lc == 'world' ? 'world' : "world-#{self.lc}"
    path = 'cgi/product_jqm.pl'
    uri = URI("https://#{subdomain}.#{domain}/#{path}")
    params = self.to_hash
    params.merge!("user_id" => user.user_id, "password" => user.password) if user
    response = Net::HTTP.post_form(uri, params)

    data = JSON.parse(response.body)
    data["status"] == 1
  else
    false
  end
end

#url(locale: DEFAULT_LOCALE) ⇒ Object

Return Product API URL



169
170
171
# File 'lib/openbeautyfacts/product.rb', line 169

def url(locale: DEFAULT_LOCALE)
  self.class.url(self.code, locale: locale)
end

#weburl(locale: nil, domain: DEFAULT_DOMAIN) ⇒ Object

Return Product web URL according to locale



175
176
177
178
179
180
181
182
# File 'lib/openbeautyfacts/product.rb', line 175

def weburl(locale: nil, domain: DEFAULT_DOMAIN)
  locale ||= self.lc || DEFAULT_LOCALE

  if self.code && prefix = LOCALE_WEBURL_PREFIXES[locale]
    path = "#{prefix}/#{self.code}"
    "https://#{locale}.#{domain}/#{path}"
  end
end