freckle 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rest-client", "1.6.1"
4
+ gem "json", "1.4.6"
5
+
6
+ group :test do
7
+ gem "fakeweb", "1.3.0"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ fakeweb (1.3.0)
5
+ json (1.4.6)
6
+ mime-types (1.16)
7
+ rest-client (1.6.1)
8
+ mime-types (>= 1.16)
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ fakeweb (= 1.3.0)
15
+ json (= 1.4.6)
16
+ rest-client (= 1.6.1)
data/README.textile ADDED
@@ -0,0 +1,41 @@
1
+ h1. Freckle
2
+
3
+ A simple RestClient-based Let's Freckle API client.
4
+
5
+ Only supports reading data.
6
+
7
+ h2. Example
8
+
9
+ Freckle.establish_conection(:account => "apitest",
10
+ :token => "lx3gi6pxdjtjn57afp8c2bv1me7g89j")
11
+
12
+ project = Freckle::Project.all.first
13
+ project.entries
14
+
15
+ h2. TODO
16
+
17
+ * CRUD
18
+
19
+ h2. License
20
+
21
+ The MIT License
22
+
23
+ Copyright (c) 2010 Matt Todd.
24
+
25
+ Permission is hereby granted, free of charge, to any person obtaining a copy
26
+ of this software and associated documentation files (the "Software"), to deal
27
+ in the Software without restriction, including without limitation the rights
28
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29
+ copies of the Software, and to permit persons to whom the Software is
30
+ furnished to do so, subject to the following conditions:
31
+
32
+ The above copyright notice and this permission notice shall be included in
33
+ all copies or substantial portions of the Software.
34
+
35
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << "test"
5
+ t.test_files = FileList['test/*_test.rb']
6
+ t.verbose = true
7
+ end
8
+
9
+ task :default => :test
data/lib/freckle.rb ADDED
@@ -0,0 +1,110 @@
1
+ # http://github.com/madrobby/freckle-apidocs
2
+
3
+ require 'logger'
4
+
5
+ require 'rest_client'
6
+ require 'json'
7
+
8
+ class Freckle
9
+ def initialize(options = {})
10
+ @account = options.delete(:account)
11
+ @token = options.delete(:token)
12
+ @logger = options.delete(:logger) || Logger.new(STDOUT)
13
+ RestClient.log = @logger
14
+ @connection = RestClient::Resource.new( "http://#{@account}.letsfreckle.com/api",
15
+ :headers => {"X-FreckleToken" => @token} )
16
+ end
17
+
18
+ def self.establish_connection(options)
19
+ @connection = new(options)
20
+ end
21
+ def self.connection
22
+ return @connection if @connection
23
+ raise RuntimeError, "Freckle.establish_connection with :account and :token first"
24
+ end
25
+
26
+ ### Query Methods
27
+
28
+ def users(options = {})
29
+ Array(JSON.parse(@connection['/users.json'].get)).flatten.map do |user|
30
+ User.new(user['user'], self)
31
+ end
32
+ end
33
+
34
+ def projects(options = {})
35
+ Array(JSON.parse(@connection['/projects.json'].get)).flatten.map do |project|
36
+ Project.new(project['project'], self)
37
+ end
38
+ end
39
+
40
+ # people: comma separated user ids
41
+ # projects: comma separated project ids
42
+ # tags: comma separated tag ids
43
+ # from: entries from this date
44
+ # to: entries to this date
45
+ # billable: true only shows billable entries; false only shows unbillable entries
46
+ def entries(options = {})
47
+ options.keys.each { |k| options["search[#{k}]"] = Array(options.delete(k)).flatten.join(',') }
48
+ Array(JSON.parse(@connection['/entries.json'].get(:params => options))).flatten.map do |entry|
49
+ Entry.new(entry['entry'], self)
50
+ end
51
+ end
52
+
53
+ ### Models
54
+
55
+ class Base
56
+ include Comparable
57
+ attr_reader :attributes
58
+ def initialize(attributes, connection = nil)
59
+ @connection = connection
60
+ @attributes = attributes
61
+ end
62
+ def id
63
+ @attributes['id']
64
+ end
65
+ def method_missing(method_name, *args)
66
+ return @attributes[method_name.to_s] if @attributes.key?(method_name.to_s)
67
+ super
68
+ end
69
+ def self.all(key = nil, options = {})
70
+ raise ArgumentError, "key is required" if key.nil?
71
+ Freckle.connection.send(key, options)
72
+ end
73
+ def self.first(options = {})
74
+ self.all(options).first
75
+ end
76
+ def <=>(other)
77
+ [self.class, self.id] <=> [other.class, other.id]
78
+ end
79
+ end
80
+
81
+ class User < Base
82
+ def self.all(options = {})
83
+ super(:users, options)
84
+ end
85
+ end
86
+
87
+ class Project < Base
88
+ def self.all(options = {})
89
+ super(:projects, options)
90
+ end
91
+ def entries(options = {})
92
+ projects = (options.delete(:projects) || [])
93
+ projects.push(self.id) unless projects.include?(self.id)
94
+ @connection.entries(options.merge(:projects => projects))
95
+ end
96
+ end
97
+
98
+ class Entry < Base
99
+ def self.all(options = {})
100
+ super(:entries, options)
101
+ end
102
+ def project(options = {})
103
+ @connection.projects(options).detect{ |project| project.id == self.project_id }
104
+ end
105
+ def user(options = {})
106
+ @connection.users(options).detect{ |user| user.id == self.user_id }
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,14 @@
1
+ [
2
+ {"entry":{"created_at":"2010-07-22T10:02:00Z","billable":true,"minutes":240,"updated_at":"2010-07-22T10:02:00Z","recently_updated_at":"2010-07-22T10:02:00Z","project_id":8475,"url":null,"time_to":null,"id":311207,"date":"2010-07-24","user_id":5543,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
3
+
4
+ {"entry":{"created_at":"2010-07-21T10:10:54Z","billable":true,"minutes":120,"updated_at":"2010-07-21T10:10:54Z","recently_updated_at":"2010-07-21T10:10:54Z","project_id":19618,"url":null,"time_to":null,"id":309459,"date":"2010-07-21","user_id":5543,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
5
+ {"entry":{"created_at":"2010-07-21T09:48:13Z","billable":true,"minutes":15,"updated_at":"2010-07-21T09:48:13Z","recently_updated_at":"2010-07-21T09:48:13Z","project_id":19618,"url":null,"time_to":null,"id":309421,"date":"2010-07-21","user_id":5543,"formatted_description":"","description_text":null,"time_from":null,"description":"foobar","invoiced_at":null,"project_invoice_id":null}},
6
+
7
+ {"entry":{"created_at":"2010-07-22T09:34:09Z","billable":true,"minutes":180,"updated_at":"2010-07-22T09:34:09Z","recently_updated_at":"2010-07-22T09:34:09Z","project_id":19618,"url":null,"time_to":null,"id":311146,"date":"2010-07-21","user_id":5538,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
8
+ {"entry":{"created_at":"2010-07-21T09:49:13Z","billable":true,"minutes":15,"updated_at":"2010-07-21T09:49:13Z","recently_updated_at":"2010-07-21T09:49:13Z","project_id":19618,"url":null,"time_to":null,"id":309427,"date":"2010-07-21","user_id":5538,"formatted_description":"","description_text":null,"time_from":null,"description":"foobar","invoiced_at":null,"project_invoice_id":null}},
9
+
10
+ {"entry":{"created_at":"2010-07-22T09:30:01Z","billable":true,"minutes":180,"updated_at":"2010-07-22T09:30:01Z","recently_updated_at":"2010-07-22T09:30:01Z","project_id":19618,"url":null,"time_to":null,"id":311144,"date":"2010-07-21","user_id":5543,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
11
+ {"entry":{"created_at":"2010-06-17T18:25:34Z","billable":true,"minutes":120,"updated_at":"2010-06-17T18:25:34Z","recently_updated_at":"2010-06-17T18:25:34Z","project_id":19618,"url":null,"time_to":null,"id":259336,"date":"2010-06-17","user_id":5543,"formatted_description":null,"description_text":null,"time_from":null,"description":"","invoiced_at":null,"project_invoice_id":null}},
12
+
13
+ {"entry":{"created_at":"2010-06-17T18:26:34Z","billable":true,"minutes":120,"updated_at":"2010-06-17T18:26:34Z","recently_updated_at":"2010-06-17T18:26:34Z","project_id":8475,"url":null,"time_to":null,"id":259339,"date":"2010-06-17","user_id":5543,"formatted_description":"","description_text":null,"time_from":null,"description":"new tag, other tag","invoiced_at":null,"project_invoice_id":null}}
14
+ ]
@@ -0,0 +1,10 @@
1
+ [
2
+ {"entry":{"created_at":"2010-07-21T10:10:54Z","billable":true,"minutes":120,"updated_at":"2010-07-21T10:10:54Z","recently_updated_at":"2010-07-21T10:10:54Z","project_id":19618,"url":null,"time_to":null,"id":309459,"date":"2010-07-21","user_id":5543,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
3
+ {"entry":{"created_at":"2010-07-21T09:48:13Z","billable":true,"minutes":15,"updated_at":"2010-07-21T09:48:13Z","recently_updated_at":"2010-07-21T09:48:13Z","project_id":19618,"url":null,"time_to":null,"id":309421,"date":"2010-07-21","user_id":5543,"formatted_description":"","description_text":null,"time_from":null,"description":"foobar","invoiced_at":null,"project_invoice_id":null}},
4
+
5
+ {"entry":{"created_at":"2010-07-22T09:34:09Z","billable":true,"minutes":180,"updated_at":"2010-07-22T09:34:09Z","recently_updated_at":"2010-07-22T09:34:09Z","project_id":19618,"url":null,"time_to":null,"id":311146,"date":"2010-07-21","user_id":5538,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
6
+ {"entry":{"created_at":"2010-07-21T09:49:13Z","billable":true,"minutes":15,"updated_at":"2010-07-21T09:49:13Z","recently_updated_at":"2010-07-21T09:49:13Z","project_id":19618,"url":null,"time_to":null,"id":309427,"date":"2010-07-21","user_id":5538,"formatted_description":"","description_text":null,"time_from":null,"description":"foobar","invoiced_at":null,"project_invoice_id":null}},
7
+
8
+ {"entry":{"created_at":"2010-07-22T09:30:01Z","billable":true,"minutes":180,"updated_at":"2010-07-22T09:30:01Z","recently_updated_at":"2010-07-22T09:30:01Z","project_id":19618,"url":null,"time_to":null,"id":311144,"date":"2010-07-21","user_id":5543,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
9
+ {"entry":{"created_at":"2010-06-17T18:25:34Z","billable":true,"minutes":120,"updated_at":"2010-06-17T18:25:34Z","recently_updated_at":"2010-06-17T18:25:34Z","project_id":19618,"url":null,"time_to":null,"id":259336,"date":"2010-06-17","user_id":5543,"formatted_description":null,"description_text":null,"time_from":null,"description":"","invoiced_at":null,"project_invoice_id":null}}
10
+ ]
@@ -0,0 +1,4 @@
1
+ [
2
+ {"entry":{"created_at":"2010-07-22T09:34:09Z","billable":true,"minutes":180,"updated_at":"2010-07-22T09:34:09Z","recently_updated_at":"2010-07-22T09:34:09Z","project_id":19618,"url":null,"time_to":null,"id":311146,"date":"2010-07-21","user_id":5538,"formatted_description":"freckle restful api test","description_text":null,"time_from":null,"description":"freckle restful api test","invoiced_at":null,"project_invoice_id":null}},
3
+ {"entry":{"created_at":"2010-07-21T09:49:13Z","billable":true,"minutes":15,"updated_at":"2010-07-21T09:49:13Z","recently_updated_at":"2010-07-21T09:49:13Z","project_id":19618,"url":null,"time_to":null,"id":309427,"date":"2010-07-21","user_id":5538,"formatted_description":"","description_text":null,"time_from":null,"description":"foobar","invoiced_at":null,"project_invoice_id":null}}
4
+ ]
@@ -0,0 +1,4 @@
1
+ [
2
+ {"project":{"name":"A new Company","created_at":"2010-06-08T00:53:20Z","billable":true,"updated_at":"2010-06-08T00:53:20Z","account_id":5039,"id":19618,"enabled":true,"user_id":null,"budget":null,"stepping":15,"invoice_recipient_details":null}},
3
+ {"project":{"name":"Fixture Company","created_at":"2009-10-16T09:04:50Z","billable":true,"updated_at":"2009-11-01T14:54:39Z","account_id":5039,"id":8475,"enabled":true,"user_id":null,"budget":null,"stepping":5,"invoice_recipient_details":null}}
4
+ ]
@@ -0,0 +1,3 @@
1
+ [
2
+ {"user":{"id":5538,"last_name":"Freckle","time_format":"fraction","login":"admin","first_name":"Lets","email":"apitestadmin@letsfreckle.com"}}
3
+ ]
@@ -0,0 +1,91 @@
1
+ require 'test_helper'
2
+
3
+ class FreckleTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @logger = Logger.new(File.join(File.dirname(__FILE__), 'test.log'))
7
+ @connection = Freckle.new(:account => @account = "test",
8
+ :token => @token = "test",
9
+ :logger => @logger)
10
+ end
11
+
12
+ def teardown
13
+ Freckle.send(:instance_variable_set, :@connection, nil)
14
+ end
15
+
16
+ ### Query Methods
17
+
18
+ def test_users
19
+ assert !@connection.users.empty?
20
+ end
21
+
22
+ def test_projects
23
+ assert !@connection.projects.empty?
24
+ end
25
+
26
+ def test_entries
27
+ assert !@connection.entries.empty?
28
+ end
29
+
30
+ ### Models
31
+
32
+ def test_users_return_user_model
33
+ assert user = @connection.users.first
34
+ assert user.is_a?(Freckle::User)
35
+ end
36
+
37
+ def test_projects_return_project_model
38
+ assert project = @connection.projects.first
39
+ assert project.is_a?(Freckle::Project)
40
+ end
41
+
42
+ def test_entries_return_entry_model
43
+ assert entry = @connection.entries.first
44
+ assert entry.is_a?(Freckle::Entry)
45
+ end
46
+
47
+ def test_user_model_attributes_are_available_as_methods
48
+ assert user = @connection.users.first
49
+ assert_equal user.id, user.attributes['id']
50
+ assert_equal user.first_name, user.attributes['first_name']
51
+ assert_equal user.last_name, user.attributes['last_name']
52
+ end
53
+
54
+ ### Associations
55
+
56
+ def test_project_model_can_query_for_its_entries
57
+ assert project = @connection.projects.first
58
+ project.entries.each do |entry|
59
+ assert_equal project, entry.project
60
+ end
61
+ end
62
+
63
+ ### Filtering
64
+
65
+ def test_entries_can_filter_by_user
66
+ assert user = @connection.users.first
67
+ assert project = @connection.projects.first
68
+ @connection.entries(:people => [user.id]).each do |entry|
69
+ assert_equal user, entry.user
70
+ end
71
+ end
72
+
73
+ ### Singleton Connection
74
+
75
+ def test_user_all_without_established_connection_raises_error
76
+ assert_raise RuntimeError, /establish_connection/ do
77
+ Freckle::User.all
78
+ end
79
+ end
80
+
81
+ def test_user_all_matches_users
82
+ Freckle.establish_connection(:account => @account, :token => @token, :logger => @logger)
83
+ assert_equal @connection.users, Freckle::User.all
84
+ end
85
+
86
+ def test_user_first_matches_first_user
87
+ Freckle.establish_connection(:account => @account, :token => @token, :logger => @logger)
88
+ assert_equal @connection.users.first, Freckle::User.first
89
+ end
90
+
91
+ end
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'freckle')
5
+
6
+ require 'test/unit'
7
+ require 'fakeweb'
8
+ FakeWeb.allow_net_connect = false
9
+
10
+ { "http://test.letsfreckle.com/api/users.json" => "users",
11
+ "http://test.letsfreckle.com/api/projects.json" => "projects",
12
+ "http://test.letsfreckle.com/api/entries.json" => "entries",
13
+ "http://test.letsfreckle.com/api/entries.json?search[projects]=19618" => "entries_for_project",
14
+ "http://test.letsfreckle.com/api/entries.json?search[people]=5538" => "entries_for_user"
15
+ }.each do |(uri, fixture)|
16
+ FakeWeb.register_uri(:get, uri, :body => File.read(File.join(File.dirname(__FILE__), "fixtures", "%s.json" % fixture)))
17
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: freckle
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Matt Todd
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-23 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rest-client
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 6
33
+ - 1
34
+ version: 1.6.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: json
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ hash: 11
46
+ segments:
47
+ - 1
48
+ - 4
49
+ - 6
50
+ version: 1.4.6
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: fakeweb
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - "="
60
+ - !ruby/object:Gem::Version
61
+ hash: 27
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 0
66
+ version: 1.3.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ description: Let's Freckle API Client
70
+ email: mtodd@highgroove.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files: []
76
+
77
+ files:
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - README.textile
81
+ - Rakefile
82
+ - lib/freckle.rb
83
+ - test/fixtures/entries.json
84
+ - test/fixtures/entries_for_project.json
85
+ - test/fixtures/entries_for_user.json
86
+ - test/fixtures/projects.json
87
+ - test/fixtures/users.json
88
+ - test/freckle_test.rb
89
+ - test/test_helper.rb
90
+ has_rdoc: true
91
+ homepage: http://github.com/reddavis/freckly
92
+ licenses: []
93
+
94
+ post_install_message:
95
+ rdoc_options: []
96
+
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project:
120
+ rubygems_version: 1.3.7
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: A Ruby client for the Let's Freckle API
124
+ test_files:
125
+ - test/freckle_test.rb
126
+ - test/test_helper.rb