fatsecret-models 0.1.2
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.
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +46 -0
- data/README.md +145 -0
- data/Rakefile +16 -0
- data/fatsecret.gemspec +21 -0
- data/lib/fatsecret-models.rb +142 -0
- data/lib/fatsecret-models/connection.rb +90 -0
- data/lib/fatsecret-models/models/base.rb +74 -0
- data/lib/fatsecret-models/models/food.rb +44 -0
- data/lib/fatsecret-models/models/serving.rb +5 -0
- data/lib/fatsecret-models/relation.rb +13 -0
- data/lib/generators/fat_secret/install/USAGE +8 -0
- data/lib/generators/fat_secret/install/install_generator.rb +13 -0
- data/lib/generators/fat_secret/install/templates/fatsecret.rb +14 -0
- data/spec/connection/conection_spec.rb +76 -0
- data/spec/fatsecret_spec.rb +29 -0
- data/spec/models/base_spec.rb +56 -0
- data/spec/models/food_spec.rb +128 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/active_model_lint.rb +16 -0
- data/spec/support/set_keys.rb +8 -0
- data/spec/support/vcr.rb +20 -0
- metadata +180 -0
data/.gitignore
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fatsecret-api (0.1.0)
|
5
|
+
active_attr
|
6
|
+
activemodel (~> 3.0)
|
7
|
+
json (~> 1.5)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
active_attr (0.6.0)
|
13
|
+
activemodel (>= 3.0.2, < 4.1)
|
14
|
+
activesupport (>= 3.0.2, < 4.1)
|
15
|
+
activemodel (3.2.8)
|
16
|
+
activesupport (= 3.2.8)
|
17
|
+
builder (~> 3.0.0)
|
18
|
+
activesupport (3.2.8)
|
19
|
+
i18n (~> 0.6)
|
20
|
+
multi_json (~> 1.0)
|
21
|
+
builder (3.0.0)
|
22
|
+
diff-lcs (1.1.3)
|
23
|
+
fakeweb (1.3.0)
|
24
|
+
i18n (0.6.0)
|
25
|
+
json (1.7.4)
|
26
|
+
multi_json (1.3.6)
|
27
|
+
rake (0.9.2.2)
|
28
|
+
rspec (2.11.0)
|
29
|
+
rspec-core (~> 2.11.0)
|
30
|
+
rspec-expectations (~> 2.11.0)
|
31
|
+
rspec-mocks (~> 2.11.0)
|
32
|
+
rspec-core (2.11.1)
|
33
|
+
rspec-expectations (2.11.2)
|
34
|
+
diff-lcs (~> 1.1.3)
|
35
|
+
rspec-mocks (2.11.2)
|
36
|
+
vcr (2.2.4)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
fakeweb
|
43
|
+
fatsecret-api!
|
44
|
+
rake
|
45
|
+
rspec
|
46
|
+
vcr
|
data/README.md
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
FatSecret Gem
|
2
|
+
=============
|
3
|
+
|
4
|
+
Introduction
|
5
|
+
------------
|
6
|
+
An activemodel compliant wrapper to the FatSecret api. You need to register with FatSecret to get
|
7
|
+
a key and secret. At the moment only the food search, and get methods are implemented. More methods
|
8
|
+
can be easily implemented. See development for more information
|
9
|
+
|
10
|
+
Installation
|
11
|
+
------------
|
12
|
+
If you are using bundler, you put this in your Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
source :rubygems
|
16
|
+
gem 'fatsecret-models', :git => 'https://github.com/joeyjoejoejr/Fatsecret.git'
|
17
|
+
```
|
18
|
+
Then run bundle install
|
19
|
+
|
20
|
+
or `gem install fatsecret-models`
|
21
|
+
|
22
|
+
Useage
|
23
|
+
------
|
24
|
+
|
25
|
+
Rails:
|
26
|
+
|
27
|
+
run `rails generate fatsecret::install`
|
28
|
+
this will create a `fatsecret.rb` initializer file in `config/initializers`
|
29
|
+
fill in your fatsecret key and secret. Make sure to exclude this file from version control
|
30
|
+
|
31
|
+
|
32
|
+
Ruby:
|
33
|
+
|
34
|
+
You must set up configuration before instantiating any of the FatSecret classes:
|
35
|
+
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
FatSecret.configure do |config|
|
39
|
+
config.api_key = <your key>
|
40
|
+
config.api_secret = <your secret key>
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
`FatSecret::Connection` is a lightweight wrapper of the api and can be used alone.
|
45
|
+
It currently has a search, and a get method. Both take three arguments and return a ruby hash.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
connection = FatSecret::Conection.new
|
49
|
+
connection.search(method, searchArguments, additionalArguments)
|
50
|
+
connection.get(method, ID, additionalArguments)
|
51
|
+
```
|
52
|
+
|
53
|
+
A real world example:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
connection = FatSecret::Connection.new
|
57
|
+
connection.search :food, "Apple", :max_results => "10"
|
58
|
+
connection.get :food, 12345
|
59
|
+
```
|
60
|
+
|
61
|
+
`FatSecret::Food` is an ActiveModel Compliant representation of the api data that
|
62
|
+
fits a number of useful rails model idioms. Usage is simple.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
foodlist = FatSecret::Food.find_by_name("Apple") # returns an array of Food objects
|
66
|
+
first_food = foodlist.first.reload #returns a full food model from the api
|
67
|
+
first_food.servings.first #returns the first serving object
|
68
|
+
```
|
69
|
+
|
70
|
+
You can also instantiate and create your own food objects using mass assignment
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
food = FatSecret::Food.new(:food_id => 12345, :food_name => "Bad and Plenties")
|
74
|
+
food.servings.new(:calories => "45", :vitamin_a => "millions of mgs")
|
75
|
+
food.servings_attributes = [{array => of}, {hashes => ""}]
|
76
|
+
```
|
77
|
+
|
78
|
+
See the `food_spec.rb` file for more examples
|
79
|
+
|
80
|
+
Development
|
81
|
+
-------------
|
82
|
+
|
83
|
+
Setup:
|
84
|
+
|
85
|
+
```
|
86
|
+
git clone 'https://github.com/joeyjoejoejr/Fatsecret.git'
|
87
|
+
cd Fatsecret
|
88
|
+
git checkout 'active_model'
|
89
|
+
bundle install
|
90
|
+
```
|
91
|
+
|
92
|
+
You'll need to set up your api-key and api-secret in the `spec/support/set_keys` files
|
93
|
+
then run the specs
|
94
|
+
|
95
|
+
```
|
96
|
+
bundle exec rspec spec/
|
97
|
+
```
|
98
|
+
|
99
|
+
Please submit pull requests with fixes, updates, new models.
|
100
|
+
|
101
|
+
Setting up a new model
|
102
|
+
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# file "/lib/fatsecret.rb"
|
106
|
+
require "fatsecret/models/your_new_model.rb"
|
107
|
+
```
|
108
|
+
Most of what you need is in the base class
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
"lib/fatsecret/models/your_new_model"
|
112
|
+
module FatSecret
|
113
|
+
class YourNewModel < FatSecret::Base
|
114
|
+
#predefine attributes for validations, others will be created dynamically
|
115
|
+
attribute :monkey, :type => String, :default => 'Oooh, ohh, Ahh'
|
116
|
+
|
117
|
+
validates :monkey, :presence => True
|
118
|
+
|
119
|
+
#creates an instance of FatSecret::Relation so that mass assigment and
|
120
|
+
#"food_object.insects.new" will work. You will need to create that related model.
|
121
|
+
has_many :insects
|
122
|
+
|
123
|
+
#this model has access to the connection object so you can define methods
|
124
|
+
#this should all be customized to deal with how Fatsecret returns
|
125
|
+
def self.find(id, args = {})
|
126
|
+
attrs = connection.get(api_method, id.to_s, args)
|
127
|
+
attrs['your_new_model']['insect_attributes'] = attrs['your_new_model']['insects']['insect']
|
128
|
+
attrs['your_new_model'].delete 'insects'
|
129
|
+
self.new attrs['your_new_model']
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.find_by_name(name, args = {})
|
133
|
+
results = connection.search(api_method, name, args)
|
134
|
+
return_results = []
|
135
|
+
results['your_new_models']['your_new_model'].each do |thing|
|
136
|
+
return_results.push self.new thing
|
137
|
+
end
|
138
|
+
return_results
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class Insect < FatSecret::Base
|
143
|
+
end
|
144
|
+
end
|
145
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
RSpec::Core::RakeTask.new('spec')
|
3
|
+
|
4
|
+
# Setting up default task
|
5
|
+
desc "Run specs"
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
namespace :fatsecret do
|
9
|
+
|
10
|
+
current_path = File.dirname(__FILE__)
|
11
|
+
|
12
|
+
desc "Install fatsecret-api"
|
13
|
+
task :install do
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/fatsecret.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'fatsecret-models'
|
3
|
+
s.version = '0.1.2'
|
4
|
+
s.date = '2012-08-21'
|
5
|
+
s.summary = "An active_model compliant wrapper for FatSecret API"
|
6
|
+
s.description = "An active_model compliant wrapper for FatSecret API"
|
7
|
+
s.authors = ["Joseph Jackson", "Ibrahim Muhammad"]
|
8
|
+
s.email = 'cpmhjoe@gmail.com'
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.require_paths = ["lib"]
|
11
|
+
s.homepage = 'http://www.github.com/joeyjoejoejr/fatsecret'
|
12
|
+
|
13
|
+
s.add_runtime_dependency 'json', '~> 1.5'
|
14
|
+
s.add_runtime_dependency 'activemodel', '~> 3.0'
|
15
|
+
s.add_runtime_dependency 'active_attr'
|
16
|
+
|
17
|
+
s.add_development_dependency 'rake'
|
18
|
+
s.add_development_dependency 'rspec'
|
19
|
+
s.add_development_dependency 'vcr'
|
20
|
+
s.add_development_dependency 'fakeweb'
|
21
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'openssl'
|
6
|
+
require 'cgi'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
#fatsecret files
|
10
|
+
require 'fatsecret-models/connection'
|
11
|
+
require 'fatsecret-models/relation'
|
12
|
+
require 'fatsecret-models/models/base'
|
13
|
+
require 'fatsecret-models/models/serving'
|
14
|
+
require 'fatsecret-models/models/food'
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
module FatSecret
|
19
|
+
class << self
|
20
|
+
attr_accessor :configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.configure
|
24
|
+
self.configuration ||= Configuration.new
|
25
|
+
yield(configuration)
|
26
|
+
return self.configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
class Configuration
|
30
|
+
attr_accessor :api_key, :api_secret, :api_url, :api_methods, :oauth_token
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@api_url = "http://platform.fatsecret.com/rest/server.api"
|
34
|
+
@api_methods = %w{food recipe}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#class FatSecret
|
40
|
+
|
41
|
+
# @@key = ""
|
42
|
+
# @@secret = ""
|
43
|
+
|
44
|
+
# SHA1 = "HMAC-SHA1"
|
45
|
+
# SITE = "http://platform.fatsecret.com/keyrest/server.api"
|
46
|
+
# DIGEST = OpenSSL::Digest::Digest.new('sha1')
|
47
|
+
|
48
|
+
# def self.init(key, secret)
|
49
|
+
# @@key = key
|
50
|
+
# @@secret = secret
|
51
|
+
# return nil #don't return the secret key
|
52
|
+
# end
|
53
|
+
|
54
|
+
|
55
|
+
# #--------------------------------
|
56
|
+
# #--- Food Functionality
|
57
|
+
# #--------------------------------
|
58
|
+
|
59
|
+
# def self.search_food(expression)
|
60
|
+
# query = {
|
61
|
+
# :method => 'foods.search',
|
62
|
+
# :search_expression => expression.esc
|
63
|
+
# }
|
64
|
+
# get(query)
|
65
|
+
# end
|
66
|
+
|
67
|
+
# def self.food(id)
|
68
|
+
# query = {
|
69
|
+
# :method => 'food.get',
|
70
|
+
# :food_id => id
|
71
|
+
# }
|
72
|
+
# get(query)
|
73
|
+
# end
|
74
|
+
|
75
|
+
# #--------------------------------
|
76
|
+
# #--- Recipe Functionality
|
77
|
+
# #--------------------------------
|
78
|
+
|
79
|
+
# def self.search_recipes(expression,max_results=20)
|
80
|
+
# query = {
|
81
|
+
# :method => 'recipes.search',
|
82
|
+
# :search_expression => expression.esc,
|
83
|
+
# :max_results => max_results
|
84
|
+
# }
|
85
|
+
# get(query)
|
86
|
+
# end
|
87
|
+
|
88
|
+
# def self.recipe(id)
|
89
|
+
# query = {
|
90
|
+
# :method => 'recipe.get',
|
91
|
+
# :recipe_id => id
|
92
|
+
# }
|
93
|
+
# get(query)
|
94
|
+
# end
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
# private
|
99
|
+
|
100
|
+
# def self.get(query)
|
101
|
+
# params = {
|
102
|
+
# :format => 'json',
|
103
|
+
# :oauth_consumer_key => @@key,
|
104
|
+
# :oauth_nonce => "1234",
|
105
|
+
# :oauth_signature_method => SHA1,
|
106
|
+
# :oauth_timestamp => Time.now.to_i,
|
107
|
+
# :oauth_version => "1.0",
|
108
|
+
# }
|
109
|
+
# params.merge!(query)
|
110
|
+
# sorted_params = params.sort {|a, b| a.first.to_s <=> b.first.to_s}
|
111
|
+
# base = base_string("GET", sorted_params)
|
112
|
+
# http_params = http_params("GET", params)
|
113
|
+
# sig = sign(base).esc
|
114
|
+
# uri = uri_for(http_params, sig)
|
115
|
+
# results = JSON.parse(Net::HTTP.get(uri))
|
116
|
+
# end
|
117
|
+
|
118
|
+
# def self.base_string(http_method, param_pairs)
|
119
|
+
# param_str = param_pairs.collect{|pair| "#{pair.first}=#{pair.last}"}.join('&')
|
120
|
+
# list = [http_method.esc, SITE.esc, param_str.esc]
|
121
|
+
# list.join("&")
|
122
|
+
# end
|
123
|
+
|
124
|
+
# def self.http_params(method, args)
|
125
|
+
# pairs = args.sort {|a, b| a.first.to_s <=> b.first.to_s}
|
126
|
+
# list = []
|
127
|
+
# pairs.inject(list) {|arr, pair| arr << "#{pair.first.to_s}=#{pair.last}"}
|
128
|
+
# list.join("&")
|
129
|
+
# end
|
130
|
+
|
131
|
+
# def self.sign(base, token='')
|
132
|
+
# secret_token = "#{@@secret.esc}&#{token.esc}"
|
133
|
+
# base64 = Base64.encode64(OpenSSL::HMAC.digest(DIGEST, secret_token, base)).gsub(/\n/, '')
|
134
|
+
# end
|
135
|
+
|
136
|
+
# def self.uri_for(params, signature)
|
137
|
+
# parts = params.split('&')
|
138
|
+
# parts << "oauth_signature=#{signature}"
|
139
|
+
# URI.parse("#{SITE}?#{parts.join('&')}")
|
140
|
+
# end
|
141
|
+
|
142
|
+
#end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def esc
|
5
|
+
CGI.escape(self).gsub("%7E", "~").gsub("+", "%20")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module FatSecret
|
10
|
+
class Connection
|
11
|
+
def initialize
|
12
|
+
@config = FatSecret.configuration
|
13
|
+
unless @config && @config && @config.api_secret
|
14
|
+
raise RuntimeError, "One or more api_keys not set"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def search (method, expression = "", args = {})
|
19
|
+
is_api_method method
|
20
|
+
|
21
|
+
query = {:method => "#{method}s.search",
|
22
|
+
:search_expression => expression.esc}
|
23
|
+
query.merge!(args)
|
24
|
+
api_get(query)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get (method, id, args = {})
|
28
|
+
is_api_method method
|
29
|
+
|
30
|
+
query = {:method => "#{method}.get",
|
31
|
+
"#{method}_id" => id}
|
32
|
+
query.merge!(args)
|
33
|
+
|
34
|
+
#add oauth token if it is defined to make it ready for more methods
|
35
|
+
query[oauth_token] = @config.oauth_token if @config.oauth_token
|
36
|
+
api_get(query)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def is_api_method (method)
|
42
|
+
unless @config.api_methods.include? method
|
43
|
+
raise TypeError, "#{method} api_method not defined"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def api_get(query)
|
48
|
+
params = {
|
49
|
+
:format => 'json',
|
50
|
+
:oauth_consumer_key => @config.api_key,
|
51
|
+
:oauth_nonce => Digest::MD5.hexdigest(rand(11).to_s),
|
52
|
+
:oauth_signature_method => "HMAC-SHA1",
|
53
|
+
:oauth_timestamp => Time.now.to_i,
|
54
|
+
:oauth_version => "1.0",
|
55
|
+
}
|
56
|
+
params.merge!(query)
|
57
|
+
sorted_params = params.sort {|a, b| a.first.to_s <=> b.first.to_s}
|
58
|
+
base = base_string("GET", sorted_params)
|
59
|
+
http_params = http_params("GET", params)
|
60
|
+
sig = sign(base).esc
|
61
|
+
uri = uri_for(http_params, sig)
|
62
|
+
results = JSON.parse(Net::HTTP.get(uri))
|
63
|
+
end
|
64
|
+
|
65
|
+
def base_string(http_method, param_pairs)
|
66
|
+
param_str = param_pairs.collect{|pair| "#{pair.first}=#{pair.last}"}.join('&')
|
67
|
+
list = [http_method.esc, @config.api_url.esc, param_str.esc]
|
68
|
+
list.join("&")
|
69
|
+
end
|
70
|
+
|
71
|
+
def http_params(method, args)
|
72
|
+
pairs = args.sort {|a, b| a.first.to_s <=> b.first.to_s}
|
73
|
+
list = []
|
74
|
+
pairs.inject(list) {|arr, pair| arr << "#{pair.first.to_s}=#{pair.last}"}
|
75
|
+
list.join("&")
|
76
|
+
end
|
77
|
+
|
78
|
+
def sign(base, token='')
|
79
|
+
digest = OpenSSL::Digest::Digest.new('sha1')
|
80
|
+
secret_token = "#{@config.api_secret.esc}&#{token.esc}"
|
81
|
+
base64 = Base64.encode64(OpenSSL::HMAC.digest(digest, secret_token, base)).gsub(/\n/, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
def uri_for(params, signature)
|
85
|
+
parts = params.split('&')
|
86
|
+
parts << "oauth_signature=#{signature}"
|
87
|
+
URI.parse("#{@config.api_url}?#{parts.join('&')}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'active_attr'
|
2
|
+
|
3
|
+
module FatSecret
|
4
|
+
class Base
|
5
|
+
include ActiveAttr::Model
|
6
|
+
|
7
|
+
#Has many sets up the relationship methods needed to create new nested items
|
8
|
+
#through mass assignment. Use <class_symbol>_attributes to do so.
|
9
|
+
def self.has_many(klass_sym)
|
10
|
+
relation = FatSecret::Relation.new(sym_to_class(klass_sym))
|
11
|
+
attribute klass_sym , :default => relation
|
12
|
+
str = "#{klass_sym.to_s}_attributes="
|
13
|
+
block = lambda do |args|
|
14
|
+
args = [args] unless args.kind_of? Array
|
15
|
+
args.each { |item| send(klass_sym).new(item) if send(klass_sym)}
|
16
|
+
end
|
17
|
+
send(:define_method, str.to_sym, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
#instance methods
|
21
|
+
def initialize args = {}
|
22
|
+
@dynattrs ||= {}
|
23
|
+
super
|
24
|
+
args.each do |k,v|
|
25
|
+
#puts k.to_s + " : " + v.to_s
|
26
|
+
send (k.to_s + "=").to_sym, v
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing sym, *args
|
32
|
+
if sym =~ /^(\w+)=$/
|
33
|
+
@dynattrs ||= {}
|
34
|
+
@dynattrs[$1.to_sym] = args[0]
|
35
|
+
else
|
36
|
+
@dynattrs[sym]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
str = super
|
42
|
+
@dynattrs.merge(attributes).each do |k,v|
|
43
|
+
#iv = iv.to_s.gsub(/@/, "")
|
44
|
+
str = str.gsub(/[^=]>$/, " :#{k} => '#{v}' >")
|
45
|
+
end
|
46
|
+
return str
|
47
|
+
end
|
48
|
+
|
49
|
+
def reload
|
50
|
+
if self.class.respond_to? :api_method and self.class.respond_to? :find
|
51
|
+
find_id = send (self.class.api_method + "_id").to_sym
|
52
|
+
self.class.find(find_id)
|
53
|
+
else
|
54
|
+
self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#Hack so that all the various sends aren't stuck in the protected space
|
59
|
+
class << self
|
60
|
+
protected :has_many
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def self.connection
|
66
|
+
@connection ||= FatSecret::Connection.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.sym_to_class(klass_sym)
|
70
|
+
klass = klass_sym.to_s.gsub(/s$/, "").split("_").map { |x| x.capitalize }.join
|
71
|
+
FatSecret.const_get(klass)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module FatSecret
|
2
|
+
class Food < FatSecret::Base
|
3
|
+
attribute :food_name, :type => String
|
4
|
+
attribute :food_id, :type => Integer
|
5
|
+
attribute :food_url, :type => String
|
6
|
+
|
7
|
+
has_many :servings
|
8
|
+
|
9
|
+
url_regex = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
|
10
|
+
|
11
|
+
validates :food_name, :presence => true
|
12
|
+
validates :food_id, :presence => true, :numericality => true
|
13
|
+
validates :food_url, :presence => true, :format => { :with => url_regex }
|
14
|
+
validate :has_serving
|
15
|
+
|
16
|
+
#Instance Methods
|
17
|
+
|
18
|
+
def self.find(id, args = {})
|
19
|
+
attrs = connection.get(api_method, id.to_s, args)
|
20
|
+
attrs['food']['servings_attributes'] = attrs['food']['servings']['serving']
|
21
|
+
attrs['food'].delete 'servings'
|
22
|
+
self.new attrs['food']
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.find_by_name(name, args = {})
|
26
|
+
results = connection.search(api_method, name, args)
|
27
|
+
return_results = []
|
28
|
+
results['foods']['food'].each do |food|
|
29
|
+
return_results.push self.new food
|
30
|
+
end
|
31
|
+
return_results
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def self.api_method
|
37
|
+
"food"
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_serving
|
41
|
+
errors.add(:base, 'must have one or more servings') if servings.empty?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
if defined? Rails
|
2
|
+
module FatSecret
|
3
|
+
module Generators
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
def copy_initializer
|
8
|
+
copy_file "fatsecret.rb", "config/initializers/fatsecret.rb"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'fatsecret-models'
|
2
|
+
|
3
|
+
FatSecret.configure do |config|
|
4
|
+
# Config options include:
|
5
|
+
# api_key
|
6
|
+
# api_secret
|
7
|
+
# api_url (defaults to the current fatsecret api http://platform.fatsecret.com/rest/server.api)
|
8
|
+
# api_methods (an array of methods for the fs api currently [food, recipies], more can be added)
|
9
|
+
# oauth_token (for future implementation with user-specific information)
|
10
|
+
#
|
11
|
+
# uncomment the following two lines and add your information
|
12
|
+
#config.api_key =
|
13
|
+
#config.api_secret =
|
14
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FatSecret::Connection do
|
4
|
+
|
5
|
+
describe "Sting method" do
|
6
|
+
it "should correctly format a sring" do
|
7
|
+
"foo~bar baz".esc.should eq "foo~bar%20baz"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "initialze" do
|
12
|
+
it "should throw an error if api_keys aren't set" do
|
13
|
+
expect {FatSecret::Connection.new()}.to raise_error(RuntimeError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "search" do
|
18
|
+
before(:each) do
|
19
|
+
set_keys
|
20
|
+
@connection = FatSecret::Connection.new()
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond_to search" do
|
24
|
+
@connection.should respond_to :search
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should reject an undefined method" do
|
28
|
+
expect {@connection.search("notfood")}.to raise_error(TypeError)
|
29
|
+
end
|
30
|
+
|
31
|
+
#searches for different methods
|
32
|
+
FatSecret.configure {}.api_methods.each do |method|
|
33
|
+
it "should return a list of #{method}s for #{method} method", :vcr do
|
34
|
+
results = @connection.search(method, "apple")
|
35
|
+
results[method + 's'].should_not be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should accept page_number and max_results arguments", :vcr do
|
40
|
+
results = @connection.search("food", "apple", :max_results => "10",
|
41
|
+
:page_number => "5")
|
42
|
+
results["foods"]["max_results"].should eq "10"
|
43
|
+
results["foods"]["page_number"].should eq "5"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return for no records found", :vcr do
|
47
|
+
results = @connection.search("food","blablabla nmek123")
|
48
|
+
results["foods"]["food"].should be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "get" do
|
53
|
+
before(:each) do
|
54
|
+
set_keys
|
55
|
+
@connection = FatSecret::Connection.new()
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should respond_to get" do
|
59
|
+
@connection.should respond_to :get
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should reject an undefined method" do
|
63
|
+
expect {@connection.get("notfood", "99967")}.to raise_error(TypeError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return a food for food.get method", :vcr do
|
67
|
+
results = @connection.get("food", "99967")
|
68
|
+
results["food"].should_not be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return a recipe for recipe.get method", :vcr do
|
72
|
+
results = @connection.get("recipe", "30633")
|
73
|
+
results["recipe"].should_not be_nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe FatSecret do
|
3
|
+
|
4
|
+
describe "configuration" do
|
5
|
+
|
6
|
+
it "responds to configure" do
|
7
|
+
FatSecret.should respond_to :configure
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return the configuration object" do
|
11
|
+
config = FatSecret.configure { |config| config.api_key, config.api_secret = "key", "secret"}
|
12
|
+
config.should be_kind_of FatSecret::Configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set the api keys with a config block" do
|
16
|
+
FatSecret.configure { |config| config.api_key, config.api_secret = "key", "secret"}
|
17
|
+
config = FatSecret.configuration
|
18
|
+
|
19
|
+
config.should be_kind_of FatSecret::Configuration
|
20
|
+
config.api_key.should eq "key"
|
21
|
+
config.api_secret.should eq "secret"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set the api keys with direct assignment" do
|
25
|
+
FatSecret.configuration.api_key = "NewKey"
|
26
|
+
FatSecret.configuration.api_key.should eq "NewKey"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_attr/mass_assignment'
|
3
|
+
|
4
|
+
|
5
|
+
describe FatSecret::Base do
|
6
|
+
it_should_behave_like "ActiveModel"
|
7
|
+
|
8
|
+
it "should not respond to save or create" do
|
9
|
+
FatSecret::Base.new.should_not respond_to :save
|
10
|
+
FatSecret::Base.new.should_not respond_to :save!
|
11
|
+
FatSecret::Base.new.should_not respond_to :create
|
12
|
+
FatSecret::Base.new.should_not respond_to :create!
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "has_many" do
|
16
|
+
before(:each) do
|
17
|
+
class FatSecret::HasManyTest
|
18
|
+
include ActiveAttr::MassAssignment
|
19
|
+
attr_accessor :first_name, :last_name
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestClass < FatSecret::Base
|
23
|
+
has_many :has_many_tests
|
24
|
+
end
|
25
|
+
|
26
|
+
@testclass = TestClass.new
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create an accessible attribute based on the class class" do
|
30
|
+
@testclass.should respond_to :has_many_tests
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return an array" do
|
34
|
+
@testclass.has_many_tests.should be_kind_of Array
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create a new instance of the class and add it to the array" do
|
38
|
+
@testclass.has_many_tests.new
|
39
|
+
@testclass.has_many_tests.first.should be_kind_of FatSecret::HasManyTest
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should destroy an associated record" do
|
43
|
+
@testclass.has_many_tests.new
|
44
|
+
@to_remove = @testclass.has_many_tests.first
|
45
|
+
@testclass.has_many_tests.delete(@to_remove)
|
46
|
+
@testclass.has_many_tests.should be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should accept nested attributes" do
|
50
|
+
@testclass.has_many_tests_attributes = {:first_name => "Joe",
|
51
|
+
:last_name => "Everyman"}
|
52
|
+
@testclass.has_many_tests.first.first_name.should eq "Joe"
|
53
|
+
@testclass.has_many_tests.first.last_name.should eq "Everyman"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FatSecret::Food do
|
4
|
+
|
5
|
+
%w(food_id food_name food_id food_url servings).each do |food_attr|
|
6
|
+
it "should respond to #{food_attr}" do
|
7
|
+
FatSecret::Food.new.should respond_to food_attr
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "validations" do
|
12
|
+
before(:each) do
|
13
|
+
@valid_attrs = { :food_name => "Blueberries", :food_id => "23",
|
14
|
+
:food_url => "http://www.example.com/one-two-three"}
|
15
|
+
@valid_serving = { :servings_attributes =>[{"calcium"=>"8", "calories"=>"200",
|
16
|
+
"carbohydrate"=>"27", "cholesterol"=>"20", "fat"=>"10",
|
17
|
+
"fiber"=>"3", "iron"=>"2", "measurement_description"=>"serving",
|
18
|
+
"metric_serving_amount"=>"142.000", "metric_serving_unit"=>"g",
|
19
|
+
"number_of_units"=>"1.000", "protein"=>"4", "saturated_fat"=>"4",
|
20
|
+
"serving_description"=>"1 serving", "serving_id"=>"141998",
|
21
|
+
"serving_url"=>"http://www.fatsecret.com/calories-nutrition/au-bon-pain/apples-blue-cheese-and-cranberries",
|
22
|
+
"sodium"=>"290", "sugar"=>"20", "vitamin_a"=>"4", "vitamin_c"=>"8"},
|
23
|
+
{"calcium"=>"8", "calories"=>"500",
|
24
|
+
"carbohydrate"=>"27", "cholesterol"=>"20", "fat"=>"10",
|
25
|
+
"fiber"=>"3", "iron"=>"2", "measurement_description"=>"serving",
|
26
|
+
"metric_serving_amount"=>"142.000", "metric_serving_unit"=>"g",
|
27
|
+
"number_of_units"=>"1.000", "protein"=>"4", "saturated_fat"=>"4",
|
28
|
+
"serving_description"=>"1 serving", "serving_id"=>"141998",
|
29
|
+
"serving_url"=>"http://www.fatsecret.com/calories-nutrition/au-bon-pain/apples-blue-cheese-and-cranberries",
|
30
|
+
"sodium"=>"290", "sugar"=>"20", "vitamin_a"=>"4", "vitamin_c"=>"8"}]
|
31
|
+
}
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be valid with valid attributes" do
|
36
|
+
food = FatSecret::Food.new(@valid_attrs)
|
37
|
+
food.servings = @valid_serving[:servings_attributes]
|
38
|
+
food.should be_valid
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should not be valid if not set", :vcr do
|
42
|
+
FatSecret::Food.new.should_not be_valid
|
43
|
+
end
|
44
|
+
|
45
|
+
[:food_name, :food_id, :food_url].each do |model_attr|
|
46
|
+
it "should not be valid without #{model_attr}" do
|
47
|
+
food = FatSecret::Food.new(@valid_attrs.merge(model_attr => ""))
|
48
|
+
food.should_not be_valid
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not be valid with a non-numerical food_id" do
|
53
|
+
food = FatSecret::Food.new(@valid_attrs.merge(:food_id => "Monkey"))
|
54
|
+
food.should_not be_valid
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should accept nested attribures for servings" do
|
58
|
+
valid = @valid_attrs.merge(@valid_serving)
|
59
|
+
food = FatSecret::Food.new(@valid_attrs)
|
60
|
+
food.should respond_to :servings
|
61
|
+
food.servings_attributes = @valid_serving[:servings_attributes]
|
62
|
+
food.servings.should_not be_empty
|
63
|
+
food.servings.first.calcium.should eq '8'
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should directly accept nested attribues' do
|
67
|
+
valid = @valid_attrs.merge(@valid_serving)
|
68
|
+
food = FatSecret::Food.new(valid)
|
69
|
+
food.should be_valid
|
70
|
+
#puts food.servings.first
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "find" do
|
75
|
+
|
76
|
+
before(:each) do
|
77
|
+
set_keys
|
78
|
+
@food = FatSecret::Food.find(99967)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should respond to find", :vcr do
|
82
|
+
FatSecret::Food.should respond_to :find
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return something", :vcr do
|
86
|
+
@food.should_not be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return a valid food model", :vcr do
|
90
|
+
@food.should be_kind_of FatSecret::Food
|
91
|
+
@food.should be_valid
|
92
|
+
@food.servings.first.should be_kind_of FatSecret::Serving
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "find_by_name" do
|
98
|
+
before(:each) do
|
99
|
+
set_keys
|
100
|
+
@food_list = FatSecret::Food.find_by_name("Apple")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should respond to find_by_name", :vcr do
|
104
|
+
FatSecret::Food.should respond_to :find_by_name
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should return an array", :vcr do
|
108
|
+
@food_list.should_not be_nil
|
109
|
+
@food_list.should be_kind_of Array
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should be a list of food objects", :vcr do
|
113
|
+
@food_list.first.should be_kind_of FatSecret::Food
|
114
|
+
@food_list.first.should_not be_valid
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "reload" do
|
120
|
+
it "should return a new model from the api", :vcr do
|
121
|
+
food_list = FatSecret::Food.find_by_name("Apple")
|
122
|
+
food = food_list.first
|
123
|
+
food.should_not be_valid
|
124
|
+
food.reload.should be_valid
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'active_model'
|
4
|
+
require 'vcr'
|
5
|
+
require 'fakeweb'
|
6
|
+
require "active_attr/rspec"
|
7
|
+
|
8
|
+
require 'fatsecret' # and any other gems you need
|
9
|
+
|
10
|
+
|
11
|
+
Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.color_enabled = true
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
shared_examples_for "ActiveModel" do
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
require 'active_model/lint'
|
4
|
+
include Test::Unit::Assertions
|
5
|
+
include ActiveModel::Lint::Tests
|
6
|
+
|
7
|
+
ActiveModel::Lint::Tests.public_instance_methods.map{|m| m.to_s}.grep(/^test/).each do |m|
|
8
|
+
example m.gsub('_',' ') do
|
9
|
+
send m
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def model
|
14
|
+
subject
|
15
|
+
end
|
16
|
+
end
|
data/spec/support/vcr.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_support/core_ext/hash/slice'
|
2
|
+
require 'active_support/core_ext/hash/except'
|
3
|
+
|
4
|
+
VCR.configure do |c|
|
5
|
+
c.cassette_library_dir = File.join("spec", "vcr")
|
6
|
+
c.hook_into :fakeweb
|
7
|
+
c.default_cassette_options = {
|
8
|
+
:match_requests_on => [:method,
|
9
|
+
VCR.request_matchers.uri_without_params(
|
10
|
+
:oauth_timestamp, :oauth_signature, :oauth_nonce)]}
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |c|
|
14
|
+
c.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
c.around(:each, :vcr) do |example|
|
16
|
+
name = example.metadata[:full_description].split(/\s+/, 2).join("/").gsub(/[^\w\/]+/, "_")
|
17
|
+
options = example.metadata.slice(:record, :match_requests_on).except(:example_group)
|
18
|
+
VCR.use_cassette(name, options) { example.call }
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fatsecret-models
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joseph Jackson
|
9
|
+
- Ibrahim Muhammad
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-08-21 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.5'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: activemodel
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '3.0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: active_attr
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rake
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: rspec
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: vcr
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: fakeweb
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
description: An active_model compliant wrapper for FatSecret API
|
128
|
+
email: cpmhjoe@gmail.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- Gemfile.lock
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- fatsecret.gemspec
|
139
|
+
- lib/fatsecret-models.rb
|
140
|
+
- lib/fatsecret-models/connection.rb
|
141
|
+
- lib/fatsecret-models/models/base.rb
|
142
|
+
- lib/fatsecret-models/models/food.rb
|
143
|
+
- lib/fatsecret-models/models/serving.rb
|
144
|
+
- lib/fatsecret-models/relation.rb
|
145
|
+
- lib/generators/fat_secret/install/USAGE
|
146
|
+
- lib/generators/fat_secret/install/install_generator.rb
|
147
|
+
- lib/generators/fat_secret/install/templates/fatsecret.rb
|
148
|
+
- spec/connection/conection_spec.rb
|
149
|
+
- spec/fatsecret_spec.rb
|
150
|
+
- spec/models/base_spec.rb
|
151
|
+
- spec/models/food_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/support/active_model_lint.rb
|
154
|
+
- spec/support/set_keys.rb
|
155
|
+
- spec/support/vcr.rb
|
156
|
+
homepage: http://www.github.com/joeyjoejoejr/fatsecret
|
157
|
+
licenses: []
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 1.8.24
|
177
|
+
signing_key:
|
178
|
+
specification_version: 3
|
179
|
+
summary: An active_model compliant wrapper for FatSecret API
|
180
|
+
test_files: []
|