Module: FoodInfo

Defined in:
lib/food_info.rb,
lib/food_info/errors.rb,
lib/food_info/version.rb,
lib/food_info/adapters.rb,
lib/food_info/cache_adapters.rb,
lib/food_info/adapters/fat_secret.rb,
lib/food_info/cache_adapters/default.rb,
lib/food_info/adapters/fat_secret/request.rb,
lib/food_info/adapters/fat_secret/data/food_item.rb,
lib/food_info/cache_adapters/mem_cache_compatible.rb,
lib/food_info/adapters/fat_secret/data/food_serving.rb,
lib/food_info/adapters/fat_secret/data/search_result.rb,
lib/food_info/adapters/fat_secret/data/search_results.rb

Defined Under Namespace

Modules: Adapters, CacheAdapters Classes: AuthorizationError, DataSourceException, NoAdapterSpecified, UnsupportedAdapter

Constant Summary collapse

ADAPTERS =

Allow extending to additional data sources in the future Each adapter should implement search and details methods.

{:fat_secret => FoodInfo::Adapters::FatSecret}
VERSION =
"0.0.7"

Class Method Summary collapse

Class Method Details

.cached(method, param, opts = {}) ⇒ Object

Implementation details =



60
61
62
63
64
# File 'lib/food_info.rb', line 60

def cached(method, param, opts = {})
  key = request_key(method, param, opts)
  
  @cache.get(key) || @cache.set(key, next_adapter.send(method, param, opts))
end

.details(id, opts = {}) ⇒ Object



52
53
54
# File 'lib/food_info.rb', line 52

def details(id, opts = {})
  cached(:details, id)
end

.establish_connection(adapter_name, opts = {}) ⇒ Object

Sets the adapter we’ll be pulling data from.

Example usage:

FoodInfo.establish_connection(:fat_secret, :key => '...', :secret => '...')

Example with cache:

require 'dalli' # Use dalli gem to interface with memcache
client = Dalli::Client.new('localhost:11211')
FoodInfo.establish_connection(:fat_secret, :key => '...', :secret => '...', :cache => client)

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/food_info.rb', line 27

def establish_connection(adapter_name, opts = {})
  klass = ADAPTERS[adapter_name.to_sym]
  raise UnsupportedAdapter.new("Requested adapter ('#{adapter_name}') is unknown") unless klass
  
  # Set up the pool of workers (net yet implemented, so defaulting to "pool" of one)
  @@pool = []
  @@cursor = 0
  (opts.delete(:pool) || 1).to_i.times do
    @@pool << klass.new(opts) 
  end
  
  # Set up the cache, if any provided
  obj = opts.delete(:cache)
  @cache = obj ? FoodInfo::CacheAdapters::MemCacheCompatible.new(obj) : FoodInfo::CacheAdapters::Default.new
  
  true
end

.next_adapterObject

FUTURE: This connection pool code won’t do much good until HTTParty is non-blocking

Raises:



67
68
69
70
71
# File 'lib/food_info.rb', line 67

def next_adapter
  raise NoAdapterSpecified.new("You must run FoodInfo.establish_connection first") unless defined?(@@pool)
  @@cursor = (@@cursor + 1) % @@pool.length
  @@pool[@@cursor]
end

.request_key(method, param, opts = {}) ⇒ Object

Convert method + args into a string for use as the cache key



74
75
76
77
78
79
# File 'lib/food_info.rb', line 74

def request_key(method, param, opts = {})
  # {:param => 123, :other => "something"} # => "other=something:param=123"
  str_opts = opts.sort{|a,b| a.to_s <=> b.to_s}.map{|pair| pair.join('=')}.join(':')
  
  "FoodInfo:#{method}:#{param}:#{str_opts}"
end

.search(q, opts = {}) ⇒ Object

Public API Methods =



48
49
50
# File 'lib/food_info.rb', line 48

def search(q, opts = {})
  cached(:search, q, opts)
end