letsfreckle-client 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'letsfreckle'
5
+
6
+ # Configure the API credentials.
7
+ LetsFreckle.configure do
8
+ account_host "apitest"
9
+ username "apitest@letsfreckle.com"
10
+ token "lx3gi6pxdjtjn57afp8c2bv1me7g89j"
11
+ end
12
+
13
+ puts "Fetch all entries:"
14
+ LetsFreckle::Entry.all.each do |entry|
15
+ puts "Entry #{entry.description} - #{entry.minutes} minutes"
16
+ end
17
+
18
+ puts "Search for entries from a specific start date and tags:"
19
+ LetsFreckle::Entry.find(:from => '2010-07-10', :tags => ['development', 'design']).each do |entry|
20
+ puts entry.description
21
+ end
22
+
23
+ puts "Fetch all projects and associated entries:"
24
+ LetsFreckle::Project.all.each do |project|
25
+ puts "Project #{project.name} has #{project.entries.size} entries"
26
+ end
27
+
28
+ puts "Fetch all tags and associated entries:"
29
+ LetsFreckle::Tag.all.each do |tag|
30
+ puts "Tag #{tag.name} has #{tag.entries.size} entries"
31
+ end
32
+
33
+ puts "Fetch all users and associated permissions:"
34
+ LetsFreckle::User.all.each do |user|
35
+ puts "User #{user.email} has following permissions: #{user.permissions}"
36
+ end
37
+
38
+
39
+
40
+
41
+
@@ -19,8 +19,11 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency("httparty", ">= 0.7.8")
23
- s.add_dependency("hashie", ">= 1.0.0")
24
- s.add_development_dependency("rspec", "~> 2.5.0")
25
- s.add_development_dependency("webmock", "~> 1.6.2")
22
+ s.add_dependency 'hashie', '~> 1.1.0'
23
+ s.add_dependency 'faraday', '~> 0.7.4'
24
+ s.add_dependency 'faraday_middleware', '~> 0.7.0'
25
+ s.add_dependency 'multi_xml', '~> 0.2.0'
26
+ s.add_development_dependency "activesupport", "~> 2.3"
27
+ s.add_development_dependency 'rspec', '~> 2.5.0'
28
+ s.add_development_dependency 'webmock', '~> 1.6.2'
26
29
  end
@@ -0,0 +1,20 @@
1
+ module Faraday
2
+ class Request
3
+ class XML < Faraday::Middleware
4
+ dependency 'active_support/all'
5
+
6
+ def initialize(app, options={})
7
+ @app = app
8
+ @options = options
9
+ end
10
+
11
+ def call(env)
12
+ if env[:method] == :post
13
+ env[:body] = env[:body].to_xml(:root => env[:body].delete(:root))
14
+ puts env[:body]
15
+ end
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Faraday
2
+ class Response
3
+ # FlattenBody is a middleware that flattens the response body, and also extends
4
+ # Hashie::Mash instances with a module that allows them to work properly with DelegateClass.
5
+ class FlattenBody < Response::Middleware
6
+ dependency 'hashie/mash'
7
+
8
+ def parse(body)
9
+ return body unless body.respond_to?(:to_a)
10
+ flattened_response = body.to_a.flatten
11
+ flattened_response.keep_if { |item| ::Hashie::Mash === item }
12
+ flattened_response.map do |mash|
13
+ # extend so that #respond_to? works nicely with DelegateClass
14
+ mash.extend(LetsFreckle::Extensions::Mash)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Faraday
2
+ class Response
3
+ class VerifyStatus < Response::Middleware
4
+ def on_complete(env)
5
+ status = env[:status].to_i
6
+ case env[:method]
7
+ when :get
8
+ raise LetsFreckle::FetchError, "Fetch failed, HTTP error: #{status}" unless status == 200
9
+ when :post
10
+ raise LetsFreckle::CreateError, "Create failed, HTTP error: #{status}" unless status == 201
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -1,7 +1,12 @@
1
- require 'hashie'
2
- require 'httparty'
3
1
  require 'delegate'
4
2
 
3
+ require 'hashie'
4
+ require 'faraday'
5
+ require 'faraday_middleware'
6
+ require 'faraday/request/xml'
7
+ require 'faraday/response/flatten_body'
8
+ require 'faraday/response/verify_status'
9
+
5
10
  require 'letsfreckle/version'
6
11
  require 'letsfreckle/extensions/mash'
7
12
  require 'letsfreckle/configuration'
@@ -2,38 +2,41 @@ module LetsFreckle
2
2
  # ClientResource should be extended by resource classes in order to gain
3
3
  # access to HTTP methods.
4
4
  module ClientResource
5
- API_URL = "https://%s.letsfreckle.com/api/%s.xml?token=%s"
6
5
 
7
- def fetch(resource, options = {})
8
- response = HTTParty.get(url(resource), :query => options, :format => :xml)
9
- verify!(response, 200) { raise FetchError, "Fetch failed, HTTP error: #{response.code}" }
10
- mashes = mashes_from_response(response)
11
- mashes.map { |m| new(m) }
6
+ def get(resource, options = {})
7
+ response = client.get do |request|
8
+ request.url relative_path_for(resource), options
9
+ end
10
+ response.body.map { |mash| new(mash) }
12
11
  end
13
12
 
14
13
  def post(resource, options = {})
15
- response = HTTParty.post(url(resource), :body => options, :format => :xml)
16
- verify!(response, 201) { raise CreateError, "Create failed, HTTP error: #{response.code}" }
14
+ client.post do |request|
15
+ request.url relative_path_for(resource)
16
+ request.headers['Content-Type'] = 'application/xml'
17
+ request.body = options
18
+ end
17
19
  end
18
20
 
19
- def url(resource)
20
- API_URL % [LetsFreckle.config.account_host, resource, LetsFreckle.config.token]
21
+ def base_api_url
22
+ "https://#{LetsFreckle.config.account_host}.letsfreckle.com"
21
23
  end
22
24
 
23
- private
24
-
25
- def verify!(response, code, &block)
26
- block.call unless response.code == code
25
+ def relative_path_for(resource)
26
+ "/api/#{resource}.xml?token=#{LetsFreckle.config.token}"
27
27
  end
28
28
 
29
- def mashes_from_response(response)
30
- return [] unless response.respond_to?(:to_a)
31
- flattened_response = response.to_a.flatten
32
- flattened_response.keep_if { |r| r.is_a?(Hash) }
33
- flattened_response.map do |h|
34
- m = Hashie::Mash.new(h)
35
- # extend so that #respond_to? works nicely with DelegateClass
36
- m.extend(Extensions::Mash)
29
+ private
30
+
31
+ def client
32
+ Faraday.new(:url => base_api_url) do |builder|
33
+ builder.use Faraday::Request::UrlEncoded
34
+ builder.use Faraday::Request::XML
35
+ builder.use Faraday::Response::FlattenBody
36
+ builder.use Faraday::Response::Mashify
37
+ builder.use Faraday::Response::ParseXml
38
+ builder.use Faraday::Response::VerifyStatus
39
+ builder.use Faraday::Adapter::NetHttp
37
40
  end
38
41
  end
39
42
  end
@@ -3,7 +3,7 @@ module LetsFreckle
3
3
  extend ClientResource
4
4
 
5
5
  def self.all
6
- fetch('entries')
6
+ get('entries')
7
7
  end
8
8
 
9
9
  # Fetches all entries. Supported options are:
@@ -14,7 +14,7 @@ module LetsFreckle
14
14
  # :to => '2012-01-01'
15
15
  # :billable => true/false
16
16
  def self.find(options = {})
17
- fetch('entries', searchable_options_from(options))
17
+ get('entries', searchable_options_from(options))
18
18
  end
19
19
 
20
20
  # Creates a new entry. Supported options are:
@@ -25,14 +25,16 @@ module LetsFreckle
25
25
  def self.create(options = {})
26
26
  raise ArgumentError, ':username config missing' unless LetsFreckle.config.username
27
27
  raise ArgumentError, ':minutes missing' unless options.has_key?(:minutes)
28
- post('entries', :entry => options.merge(:user => LetsFreckle.config.username))
28
+ post('entries', options.merge(:root => :entry, :user => LetsFreckle.config.username))
29
29
  end
30
30
 
31
31
  def self.searchable_options_from(options = {})
32
32
  options.each_with_object({}) do |(key, value), result|
33
33
  case value
34
- when Array then result["search[#{key}]"] = value.join(',')
35
- else result["search[#{key}]"] = value.to_s
34
+ when Array then
35
+ result["search[#{key}]"] = value.join(',')
36
+ else
37
+ result["search[#{key}]"] = value.to_s
36
38
  end
37
39
  end
38
40
  end
@@ -1,6 +1,5 @@
1
1
  module LetsFreckle
2
- class FetchError < StandardError
3
- end
4
- class CreateError < StandardError
5
- end
6
- end
2
+ class Error < StandardError; end
3
+ class FetchError < Error; end
4
+ class CreateError < Error; end
5
+ end
@@ -3,7 +3,7 @@ module LetsFreckle
3
3
  extend ClientResource
4
4
 
5
5
  def self.all
6
- fetch('projects')
6
+ get('projects')
7
7
  end
8
8
 
9
9
  def entries
@@ -3,7 +3,7 @@ module LetsFreckle
3
3
  extend ClientResource
4
4
 
5
5
  def self.all
6
- fetch('tags')
6
+ get('tags')
7
7
  end
8
8
 
9
9
  def entries
@@ -3,7 +3,7 @@ module LetsFreckle
3
3
  extend ClientResource
4
4
 
5
5
  def self.all
6
- fetch('users')
6
+ get('users')
7
7
  end
8
8
 
9
9
  def entries
@@ -1,3 +1,3 @@
1
1
  module Letsfreckle
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -9,7 +9,7 @@ describe LetsFreckle::Entry do
9
9
  token "secret"
10
10
  end
11
11
 
12
- stub_http_request(:get, LetsFreckle::Entry.url('entries')).to_return(:body => load_response('entries'))
12
+ stub_api_request('entries')
13
13
  entries = LetsFreckle::Entry.all
14
14
  entries.size.should == 2
15
15
 
@@ -9,7 +9,7 @@ describe LetsFreckle::Project do
9
9
  token "secret"
10
10
  end
11
11
 
12
- stub_http_request(:get, LetsFreckle::Project.url('projects')).to_return(:body => load_response('projects'))
12
+ stub_api_request('projects')
13
13
  projects = LetsFreckle::Project.all
14
14
  projects.size.should == 2
15
15
 
@@ -9,7 +9,7 @@ describe LetsFreckle::Tag do
9
9
  token "secret"
10
10
  end
11
11
 
12
- stub_http_request(:get, LetsFreckle::Tag.url('tags')).to_return(:body => load_response('tags'))
12
+ stub_api_request('tags')
13
13
  tags = LetsFreckle::Tag.all
14
14
  tags.size.should == 2
15
15
 
@@ -9,7 +9,7 @@ describe LetsFreckle::User do
9
9
  token "secret"
10
10
  end
11
11
 
12
- stub_http_request(:get, LetsFreckle::User.url('users')).to_return(:body => load_response('users'))
12
+ stub_api_request('users')
13
13
  users = LetsFreckle::User.all
14
14
  users.size.should == 2
15
15
 
@@ -2,4 +2,16 @@ module WebMockHelper
2
2
  def load_response(resource)
3
3
  File.read(File.join(File.dirname(__FILE__), '/../responses', "#{resource}.xml.response"))
4
4
  end
5
- end
5
+
6
+ def url_for_resource(resource)
7
+ "#{LetsFreckle::Entry.base_api_url}#{LetsFreckle::Entry.relative_path_for(resource)}"
8
+ end
9
+
10
+ def stub_api_request(resource)
11
+ stub_http_request(:get, url_for_resource(resource)).
12
+ with(:headers => { 'Accept' =>'*/*',
13
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
14
+ 'User-Agent' =>'Ruby' }).
15
+ to_return(:body => load_response(resource))
16
+ end
17
+ end
metadata CHANGED
@@ -1,98 +1,112 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: letsfreckle-client
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 2
9
- version: 0.1.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Ryan LeCompte
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-07-25 00:00:00 -04:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: httparty
12
+ date: 2011-08-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hashie
16
+ requirement: &70346356154000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.0
22
+ type: :runtime
22
23
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
+ version_requirements: *70346356154000
25
+ - !ruby/object:Gem::Dependency
26
+ name: faraday
27
+ requirement: &70346356153180 !ruby/object:Gem::Requirement
24
28
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- - 7
31
- - 8
32
- version: 0.7.8
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.7.4
33
33
  type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: hashie
37
34
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
35
+ version_requirements: *70346356153180
36
+ - !ruby/object:Gem::Dependency
37
+ name: faraday_middleware
38
+ requirement: &70346356152680 !ruby/object:Gem::Requirement
39
39
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 0
46
- - 0
47
- version: 1.0.0
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.7.0
48
44
  type: :runtime
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: rspec
52
45
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
46
+ version_requirements: *70346356152680
47
+ - !ruby/object:Gem::Dependency
48
+ name: multi_xml
49
+ requirement: &70346356152220 !ruby/object:Gem::Requirement
54
50
  none: false
55
- requirements:
51
+ requirements:
56
52
  - - ~>
57
- - !ruby/object:Gem::Version
58
- segments:
59
- - 2
60
- - 5
61
- - 0
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70346356152220
58
+ - !ruby/object:Gem::Dependency
59
+ name: activesupport
60
+ requirement: &70346356151760 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '2.3'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70346356151760
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &70346356151260 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
62
76
  version: 2.5.0
63
77
  type: :development
64
- version_requirements: *id003
65
- - !ruby/object:Gem::Dependency
66
- name: webmock
67
78
  prerelease: false
68
- requirement: &id004 !ruby/object:Gem::Requirement
79
+ version_requirements: *70346356151260
80
+ - !ruby/object:Gem::Dependency
81
+ name: webmock
82
+ requirement: &70346356150740 !ruby/object:Gem::Requirement
69
83
  none: false
70
- requirements:
84
+ requirements:
71
85
  - - ~>
72
- - !ruby/object:Gem::Version
73
- segments:
74
- - 1
75
- - 6
76
- - 2
86
+ - !ruby/object:Gem::Version
77
87
  version: 1.6.2
78
88
  type: :development
79
- version_requirements: *id004
80
- description: Ruby client for letsfreckle.com API that supports entries, projects, tags, and users
81
- email:
89
+ prerelease: false
90
+ version_requirements: *70346356150740
91
+ description: Ruby client for letsfreckle.com API that supports entries, projects,
92
+ tags, and users
93
+ email:
82
94
  - lecompte@gmail.com
83
- executables: []
84
-
95
+ executables:
96
+ - run-examples
85
97
  extensions: []
86
-
87
98
  extra_rdoc_files: []
88
-
89
- files:
99
+ files:
90
100
  - .gitignore
91
101
  - Gemfile
92
102
  - LICENSE
93
103
  - README.rdoc
94
104
  - Rakefile
105
+ - bin/run-examples
95
106
  - letsfreckle-client.gemspec
107
+ - lib/faraday/request/xml.rb
108
+ - lib/faraday/response/flatten_body.rb
109
+ - lib/faraday/response/verify_status.rb
96
110
  - lib/letsfreckle.rb
97
111
  - lib/letsfreckle/client_resource.rb
98
112
  - lib/letsfreckle/configuration.rb
@@ -114,39 +128,31 @@ files:
114
128
  - spec/responses/users.xml.response
115
129
  - spec/spec_helper.rb
116
130
  - spec/support/webmock_helper.rb
117
- has_rdoc: true
118
131
  homepage: http://github.com/ryanlecompte/letsfreckle-client
119
132
  licenses: []
120
-
121
133
  post_install_message:
122
134
  rdoc_options: []
123
-
124
- require_paths:
135
+ require_paths:
125
136
  - lib
126
- required_ruby_version: !ruby/object:Gem::Requirement
137
+ required_ruby_version: !ruby/object:Gem::Requirement
127
138
  none: false
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- segments:
132
- - 0
133
- version: "0"
134
- required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
144
  none: false
136
- requirements:
137
- - - ">="
138
- - !ruby/object:Gem::Version
139
- segments:
140
- - 0
141
- version: "0"
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
142
149
  requirements: []
143
-
144
150
  rubyforge_project: letsfreckle-client
145
- rubygems_version: 1.3.7
151
+ rubygems_version: 1.8.6.1
146
152
  signing_key:
147
153
  specification_version: 3
148
154
  summary: Ruby client for letsfreckle.com API
149
- test_files:
155
+ test_files:
150
156
  - spec/letsfreckle/configuration_spec.rb
151
157
  - spec/letsfreckle/entry_spec.rb
152
158
  - spec/letsfreckle/project_spec.rb