vigetlabs-unfuzzle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,109 @@
1
+ = Unfuzzle
2
+
3
+ == Description
4
+
5
+ The Unfuzzle gem provides an interface to the Unfuddle JSON API
6
+
7
+ == Installation
8
+
9
+ sudo gem install vigetlabs-unfuzzle --source=http://gems.github.com
10
+
11
+ == Usage
12
+
13
+ To get started, you'll need your Unfuddle subdomain and a valid username /
14
+ password combination:
15
+
16
+ require 'unfuzzle'
17
+
18
+ Unfuzzle.subdomain = 'viget'
19
+ Unfuzzle.username = 'bopbip'
20
+ Unfuzzle.password = 'bleep'
21
+
22
+ Once that is configured, you can start accessing data from the API.
23
+
24
+ === Projects
25
+
26
+ Pulling back a list of projects is simple. Based on the currently logged-in
27
+ user, you can see which ones he has access to:
28
+
29
+ projects = Unfuzzle.projects # => [#<Unfuzzle::Project:0x11e9280 ...> , ...]
30
+
31
+ If you don't want all projects, you can find one by its slug (or short name):
32
+
33
+ Unfuzzle.project('salty') # => #<Unfuzzle::Project:0x11e9280 ...>
34
+
35
+ Or by ID:
36
+
37
+ Unfuzzle.project(1) # => #<Unfuzzle::Project:0x11e9280 ...>
38
+
39
+ There are a few attributes available for a project:
40
+
41
+ project = Unfuzzle.projects.first
42
+ project.id # => 123
43
+ project.slug # => "salty"
44
+ project.name # => "Salty Co."
45
+ project.archived? # => false
46
+ project.created_at.strftime('%Y-%m-%d') # => "2008-07-28"
47
+
48
+ To see a list of additional attributes, take a look at the documentation for
49
+ Project.
50
+
51
+ === Milestones
52
+
53
+ Each project can have milestones. You can access these from a single project:
54
+
55
+ project.milestones # => [#<Unfuzzle::Milestone:0x10bdca8 ...>, ...]
56
+
57
+ Milestones have attributes:
58
+
59
+ milestone = project.milestones.first
60
+ milestone.id # => 1
61
+ milestone.name # => "Milestone #1"
62
+ milestone.due_on.strftime('%m/%d/%Y') # => "07/30/2008"
63
+
64
+ A full list is available in the Milestone documentation.
65
+
66
+ === Tickets
67
+
68
+ Tickets exist for a project:
69
+
70
+ ticket = project.tickets.first
71
+ ticket.title # => "Ticket #23"
72
+ ticket.number # => 23
73
+ ticket.description # => "Yo dawg, I hear you like tickets in your project ..."
74
+ ticket.status # => "closed"
75
+
76
+ And can also be associated to a milestone for the project:
77
+
78
+ ticket = project.milestones.first.tickets.first
79
+ ticket.title # => "Ticket #1"
80
+ ticket.number # => 1
81
+ ticket.description # => "Wash my car"
82
+ ticket.status # => "closed"
83
+
84
+ See the Ticket documentation for more information.
85
+
86
+ == License
87
+
88
+ Copyright (c) 2009 Patrick Reagan of Viget Labs (mailto:patrick.reagan@viget.com)
89
+
90
+ Permission is hereby granted, free of charge, to any person
91
+ obtaining a copy of this software and associated documentation
92
+ files (the "Software"), to deal in the Software without
93
+ restriction, including without limitation the rights to use,
94
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
95
+ copies of the Software, and to permit persons to whom the
96
+ Software is furnished to do so, subject to the following
97
+ conditions:
98
+
99
+ The above copyright notice and this permission notice shall be
100
+ included in all copies or substantial portions of the Software.
101
+
102
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
103
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
104
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
105
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
106
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
107
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
108
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
109
+ OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+
5
+ require 'lib/unfuzzle/version'
6
+
7
+ task :default => :test
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'unfuzzle'
11
+ s.version = Unfuzzle::Version.to_s
12
+ s.has_rdoc = true
13
+ s.extra_rdoc_files = %w(README.rdoc)
14
+ s.rdoc_options = %w(--main README.rdoc)
15
+ s.summary = "This gem provides an interface to the Unfuddle JSON API"
16
+ s.author = 'Patrick Reagan'
17
+ s.email = 'patrick.reagan@viget.com'
18
+ s.homepage = 'http://www.viget.com/extend'
19
+ s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
20
+
21
+ s.add_dependency('json', '>= 1.1.6')
22
+ end
23
+
24
+ Rake::GemPackageTask.new(spec) do |pkg|
25
+ pkg.gem_spec = spec
26
+ end
27
+
28
+ Rake::TestTask.new do |t|
29
+ t.libs << 'test'
30
+ t.test_files = FileList["test/**/*_test.rb"]
31
+ t.verbose = true
32
+ end
33
+
34
+ desc 'Generate the gemspec to serve this Gem from Github'
35
+ task :github do
36
+ file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
37
+ File.open(file, 'w') {|f| f << spec.to_ruby }
38
+ puts "Created gemspec: #{file}"
39
+ end
@@ -0,0 +1,54 @@
1
+ module Unfuzzle
2
+
3
+ # = Milestone
4
+ #
5
+ # A representation of an Unfuddle Milestone. Has the following attributes:
6
+ #
7
+ # [id] Unique identifier for this milestone
8
+ # [name] Name of the milestone
9
+ #
10
+ class Milestone
11
+
12
+ include Unfuzzle::Model
13
+
14
+ attribute :id
15
+ attribute :project_id
16
+ attribute :archived
17
+ attribute :name, :from => :title
18
+ attribute :created_timestamp, :from => :created_at
19
+ attribute :updated_timestamp, :from => :updated_at
20
+ attribute :due_datestamp, :from => :due_on
21
+
22
+ # Return a list of all milestones for a given project
23
+ def self.find_all_by_project_id(project_id)
24
+ response = Request.get("/projects/#{project_id}/milestones")
25
+ response.data.map {|data| new(data) }
26
+ end
27
+
28
+ # Has this milestone been archived?
29
+ def archived?
30
+ archived == true
31
+ end
32
+
33
+ # The DateTime that this milestone was created
34
+ def created_at
35
+ DateTime.parse(created_timestamp)
36
+ end
37
+
38
+ # The DateTime that this milestone was last updated
39
+ def updated_at
40
+ DateTime.parse(updated_timestamp)
41
+ end
42
+
43
+ # The Date that this milestone is due
44
+ def due_on
45
+ Date.parse(due_datestamp) unless due_datestamp.nil?
46
+ end
47
+
48
+ # The collection of Tickets associated to this milestone
49
+ def tickets
50
+ Ticket.find_all_by_project_id_and_milestone_id(project_id, id)
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ module Unfuzzle
2
+ module Model # :nodoc:
3
+
4
+ module ClassMethods
5
+ def attribute(name, options = {}) # :nodoc:
6
+ key = options.delete(:from) || name
7
+
8
+ class_eval %(
9
+ def #{name}
10
+ @response_data['#{key}']
11
+ end
12
+ )
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+
18
+ def initialize(response_data)
19
+ @response_data = response_data
20
+ end
21
+
22
+ end
23
+
24
+ def self.included(other)
25
+ other.send(:extend, Unfuzzle::Model::ClassMethods)
26
+ other.send(:include, Unfuzzle::Model::InstanceMethods)
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,68 @@
1
+ module Unfuzzle
2
+
3
+ # = Project
4
+ #
5
+ # Represents an Unfuddle project. Has the following attributes:
6
+ #
7
+ # [id] The unique identifier for this project
8
+ # [slug] The "short name" for this project
9
+ # [name] The name of this project
10
+ # [description] The description for the project
11
+ #
12
+ class Project
13
+
14
+ include Unfuzzle::Model
15
+
16
+ attribute :id
17
+ attribute :slug, :from => :short_name
18
+ attribute :archived
19
+ attribute :name, :from => :title
20
+ attribute :description
21
+ attribute :created_timestamp, :from => :created_at
22
+ attribute :updated_timestamp, :from => :updated_at
23
+
24
+ # Return a list of all projects to which the current user has access
25
+ def self.all
26
+ response = Request.get('/projects')
27
+ response.data.map {|data| new(data) }
28
+ end
29
+
30
+ # Find a single project by its slug (short name)
31
+ def self.find_by_slug(slug)
32
+ response = Request.get("/projects/by_short_name/#{slug}")
33
+ new(response.data)
34
+ end
35
+
36
+ # Find a single project by its ID
37
+ def self.find_by_id(id)
38
+ response = Request.get("/projects/#{id}")
39
+ new(response.data)
40
+ end
41
+
42
+ # Has this project been archived?
43
+ def archived?
44
+ archived == true
45
+ end
46
+
47
+ # The DateTime that this project was created
48
+ def created_at
49
+ DateTime.parse(created_timestamp)
50
+ end
51
+
52
+ # The DateTime that this project was last updated
53
+ def updated_at
54
+ DateTime.parse(updated_timestamp)
55
+ end
56
+
57
+ # The collection of Milestones associated to this project
58
+ def milestones
59
+ Milestone.find_all_by_project_id(id)
60
+ end
61
+
62
+ # The collection of Tickets associated to this project
63
+ def tickets
64
+ Ticket.find_all_by_project_id(id)
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Unfuzzle
2
+
3
+ # = Request
4
+ #
5
+ # A basic wrapper for GET requests to the Unfuddle API
6
+ #
7
+ class Request
8
+
9
+ # Retrieve a response from the given resource path
10
+ def self.get(resource_path)
11
+ request = new(resource_path)
12
+ request.get
13
+ end
14
+
15
+ # Create a new request for the given resource path
16
+ def initialize(resource_path)
17
+ @resource_path = resource_path
18
+ end
19
+
20
+ def endpoint_uri # :nodoc:
21
+ URI.parse("http://#{Unfuzzle.subdomain}.unfuddle.com/api/v1#{@resource_path}.json")
22
+ end
23
+
24
+ def client # :nodoc:
25
+ Net::HTTP.new(endpoint_uri.host)
26
+ end
27
+
28
+ # Retrieve a response from the current resource path
29
+ def get
30
+ request = Net::HTTP::Get.new(endpoint_uri.path)
31
+ request.basic_auth Unfuzzle.username, Unfuzzle.password
32
+
33
+ Response.new(client.request(request))
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ module Unfuzzle
2
+
3
+ # = Response
4
+ #
5
+ # A simple wrapper around an HTTP response from the Unfuddle API
6
+ #
7
+ class Response
8
+
9
+ # Create a new response from an HTTP response object
10
+ def initialize(http_response)
11
+ @http_response = http_response
12
+ end
13
+
14
+ # Was there an error produced as part of the request?
15
+ def error?
16
+ !@http_response.is_a?(Net::HTTPSuccess)
17
+ end
18
+
19
+ # Raw body of the HTTP response
20
+ def body
21
+ @http_response.body
22
+ end
23
+
24
+ # Parsed JSON response body
25
+ def data
26
+ if !error?
27
+ @parsed_data ||= JSON.parse(body)
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,55 @@
1
+ module Unfuzzle
2
+
3
+ # = Ticket
4
+ #
5
+ # Represents a single Unfuddle Ticket - is associated to a project
6
+ # and optionally a project's milestone. Has the following attributes:
7
+ #
8
+ # [id] The unique identifier for this ticket
9
+ # [number] The ticket's number - this is displayed in the web interface
10
+ # [title] The title of the ticket (short)
11
+ # [description] The full description of the ticket
12
+ # [status] The ticket's status (new / accepted / resolved / closed)
13
+ #
14
+ class Ticket
15
+
16
+ include Unfuzzle::Model
17
+
18
+ attribute :id
19
+ attribute :number
20
+ attribute :title, :from => :summary
21
+ attribute :description
22
+ attribute :due_datestamp, :from => :due_on
23
+ attribute :created_timestamp, :from => :created_at
24
+ attribute :updated_timestamp, :from => :updated_at
25
+ attribute :status
26
+
27
+ # Return a list of all tickets for an individual project
28
+ def self.find_all_by_project_id(project_id)
29
+ response = Request.get("/projects/#{project_id}/tickets")
30
+ response.data.map {|data| new(data) }
31
+ end
32
+
33
+ # Return a list of all tickets for a given milestone as part of a project
34
+ def self.find_all_by_project_id_and_milestone_id(project_id, milestone_id)
35
+ response = Request.get("/projects/#{project_id}/milestones/#{milestone_id}/tickets")
36
+ response.data.map {|data| new(data) }
37
+ end
38
+
39
+ # The DateTime that this milestone was created
40
+ def created_at
41
+ DateTime.parse(created_timestamp)
42
+ end
43
+
44
+ # The DateTime that this milestone was last updated
45
+ def updated_at
46
+ DateTime.parse(updated_timestamp)
47
+ end
48
+
49
+ # The Date that this milestone is due
50
+ def due_on
51
+ Date.parse(due_datestamp) unless due_datestamp.nil?
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module Unfuzzle
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ TINY = 0
7
+
8
+ def self.to_s # :nodoc:
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
data/lib/unfuzzle.rb ADDED
@@ -0,0 +1,72 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'json'
6
+
7
+ require 'unfuzzle/request'
8
+ require 'unfuzzle/response'
9
+ require 'unfuzzle/model'
10
+ require 'unfuzzle/project'
11
+ require 'unfuzzle/milestone'
12
+ require 'unfuzzle/ticket'
13
+
14
+ # = Unfuzzle: A simple wrapper around the Unfuddle JSON API
15
+ #
16
+ # == Quick Start
17
+ #
18
+ # To get started, you need to set the subdomain and a valid username /
19
+ # password combination:
20
+ #
21
+ # require 'rubygems'
22
+ # require 'unfuzzle'
23
+ #
24
+ # Unfuzzle.subdomain = 'viget'
25
+ # Unfuzzle.username = 'bopbip'
26
+ # Unfuzzle.password = 'bleep'
27
+ #
28
+ # From there, you can start accessing a list of projects:
29
+ #
30
+ # Project.all
31
+ #
32
+ module Unfuzzle
33
+
34
+ # Set the subdomain for all requests
35
+ def self.subdomain=(subdomain)
36
+ @subdomain = subdomain
37
+ end
38
+
39
+ # Set the username for all requests. Data retrieved from the API will be
40
+ # scoped to the data that this user has access to.
41
+ def self.username=(username)
42
+ @username = username
43
+ end
44
+
45
+ # Set the password for the supplied username
46
+ def self.password=(password)
47
+ @password = password
48
+ end
49
+
50
+ # Retrieve a project for the current user by its ID or slug
51
+ def self.project(id_or_slug)
52
+ id_or_slug.is_a?(String) ? Project.find_by_slug(id_or_slug) : Project.find_by_id(id_or_slug)
53
+ end
54
+
55
+ # Get a list of all projects for this user
56
+ def self.projects
57
+ Project.all
58
+ end
59
+
60
+ def self.subdomain # :nodoc:
61
+ @subdomain
62
+ end
63
+
64
+ def self.username # :nodoc:
65
+ @username
66
+ end
67
+
68
+ def self.password # :nodoc:
69
+ @password
70
+ end
71
+
72
+ end
@@ -0,0 +1,22 @@
1
+ [{
2
+ "archived": false,
3
+ "created_at": "2008-07-30T22:12:37Z",
4
+ "completed": true,
5
+ "title": "Milestone 1",
6
+ "person_responsible_id": 12345,
7
+ "due_on": "2008-07-30",
8
+ "updated_at": "2008-12-26T22:32:03Z",
9
+ "id": 1,
10
+ "project_id": 1
11
+ },
12
+ {
13
+ "archived": false,
14
+ "created_at": "2009-02-09T15:15:30Z",
15
+ "completed": true,
16
+ "title": "Milestone 2",
17
+ "person_responsible_id": 12344,
18
+ "due_on": "2009-02-13",
19
+ "updated_at": "2009-02-17T15:37:01Z",
20
+ "id": 2,
21
+ "project_id": 1
22
+ }]
@@ -0,0 +1,16 @@
1
+ {
2
+ "archived": false,
3
+ "short_name": "blip",
4
+ "created_at": "2008-07-28T16:57:10Z",
5
+ "title": "Blip Bleep Co.",
6
+ "close_ticket_simultaneously_default": true,
7
+ "account_id": 1,
8
+ "description": "This is the project for Blip Bleep Co.",
9
+ "enable_time_tracking": true,
10
+ "default_ticket_report_id": 0,
11
+ "updated_at": "2009-04-28T18:48:52Z",
12
+ "id": 1,
13
+ "theme": "teal",
14
+ "disk_usage": 1416,
15
+ "assignee_on_resolve": "none"
16
+ }
@@ -0,0 +1,32 @@
1
+ [{
2
+ "archived": false,
3
+ "short_name": "aa",
4
+ "created_at": "2008-07-28T16:57:10Z",
5
+ "title": "A Client",
6
+ "close_ticket_simultaneously_default": true,
7
+ "account_id": 12345,
8
+ "description": "A great project",
9
+ "enable_time_tracking": true,
10
+ "default_ticket_report_id": 0,
11
+ "updated_at": "2009-04-28T18:48:52Z",
12
+ "id": 1,
13
+ "theme": "teal",
14
+ "disk_usage": 1416,
15
+ "assignee_on_resolve": "none"
16
+ },
17
+ {
18
+ "archived": true,
19
+ "short_name": "zz",
20
+ "created_at": "2008-06-23T21:06:01Z",
21
+ "title": "Zee Client",
22
+ "close_ticket_simultaneously_default": false,
23
+ "account_id": 12345,
24
+ "description": null,
25
+ "enable_time_tracking": true,
26
+ "default_ticket_report_id": null,
27
+ "updated_at": "2009-05-20T23:15:24Z",
28
+ "id": 2,
29
+ "theme": "grey",
30
+ "disk_usage": 14008,
31
+ "assignee_on_resolve": "reporter"
32
+ }]
@@ -0,0 +1,44 @@
1
+ [{
2
+ "severity_id": null,
3
+ "hours_estimate_current": 0.0,
4
+ "resolution_description": "",
5
+ "reporter_id": 1,
6
+ "created_at": "2008-11-25T14:00:19Z",
7
+ "priority": "4",
8
+ "number": 1,
9
+ "milestone_id": 1,
10
+ "description": "Do something important",
11
+ "assignee_id": null,
12
+ "due_on": null,
13
+ "status": "closed",
14
+ "summary": "Ticket #1",
15
+ "resolution": "fixed",
16
+ "component_id": null,
17
+ "version_id": null,
18
+ "updated_at": "2008-12-31T15:51:41Z",
19
+ "id": 1,
20
+ "project_id": 1,
21
+ "hours_estimate_initial": 1.75
22
+ },
23
+ {
24
+ "severity_id": null,
25
+ "hours_estimate_current": 0.25,
26
+ "resolution_description": "",
27
+ "reporter_id": 1,
28
+ "created_at": "2009-02-09T15:17:52Z",
29
+ "priority": "3",
30
+ "number": 2,
31
+ "milestone_id": 1,
32
+ "description": "Do something else important",
33
+ "assignee_id": null,
34
+ "due_on": null,
35
+ "status": "closed",
36
+ "summary": "Ticket #2",
37
+ "resolution": "fixed",
38
+ "component_id": null,
39
+ "version_id": null,
40
+ "updated_at": "2009-02-17T15:36:40Z",
41
+ "id": 2,
42
+ "project_id": 1,
43
+ "hours_estimate_initial": 0.0
44
+ }]
@@ -0,0 +1,49 @@
1
+ # http://sneaq.net/textmate-wtf
2
+ $:.reject! { |e| e.include? 'TextMate' }
3
+
4
+ require 'rubygems'
5
+ require 'throat_punch'
6
+
7
+ require File.dirname(__FILE__) + '/../lib/unfuzzle'
8
+
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ def self.read_fixture(method_name)
13
+ file = File.dirname(__FILE__) + "/fixtures/#{method_name}.json"
14
+ JSON.parse(File.read(file))
15
+ end
16
+
17
+ def read_fixture(method_name)
18
+ self.class.read_fixture(method_name)
19
+ end
20
+
21
+ def mock_request_cycle(options)
22
+ response = Unfuzzle::Response.new(stub())
23
+
24
+ data = read_fixture(options[:data])
25
+
26
+ response.stubs(:data).with().returns(data)
27
+
28
+ Unfuzzle::Request.stubs(:get).with(options[:for]).returns(response)
29
+
30
+ response
31
+ end
32
+
33
+ def self.when_populating(klass, options, &block)
34
+ # data = options[:from].is_a?(String) ? read_fixture(options[:from])[0] : options[:from].call
35
+
36
+ context "with data populated for #{klass}" do
37
+ setup { @object = klass.new(read_fixture(options[:from])[0]) }
38
+ merge_block(&block)
39
+ end
40
+
41
+ end
42
+
43
+ def self.value_for(method_name, options)
44
+ should "have a value for :#{method_name}" do
45
+ @object.send(method_name).should == options[:is]
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ module Unfuzzle
4
+ class MilestoneTest < Test::Unit::TestCase
5
+
6
+ context "The Milestone class" do
7
+
8
+ should "be able to find all by project ID" do
9
+ project_id = 1
10
+
11
+ response = mock_request_cycle :for => "/projects/#{project_id}/milestones", :data => 'milestones'
12
+
13
+ milestones = Array.new
14
+
15
+ response.data.each do |data|
16
+ milestone = stub()
17
+ Unfuzzle::Milestone.expects(:new).with(data).returns(milestone)
18
+ milestones << milestone
19
+ end
20
+
21
+ Milestone.find_all_by_project_id(1).should == milestones
22
+ end
23
+
24
+ end
25
+
26
+ context "An instance of the Milestone class" do
27
+
28
+ when_populating Milestone, :from => 'milestones' do
29
+
30
+ value_for :id, :is => 1
31
+ value_for :project_id, :is => 1
32
+ value_for :archived, :is => false
33
+ value_for :created_timestamp, :is => '2008-07-30T22:12:37Z'
34
+ value_for :name, :is => 'Milestone 1'
35
+ value_for :due_datestamp, :is => '2008-07-30'
36
+ value_for :updated_timestamp, :is => '2008-12-26T22:32:03Z'
37
+
38
+ end
39
+
40
+ context "with a new instance" do
41
+
42
+ setup { @milestone = Milestone.new(stub()) }
43
+
44
+ should "know that it is archived" do
45
+ @milestone.stubs(:archived).with().returns(true)
46
+ @milestone.archived?.should be(true)
47
+ end
48
+
49
+ should "know that it isn't archived" do
50
+ @milestone.stubs(:archived).with().returns(false)
51
+ @milestone.archived?.should be(false)
52
+ end
53
+
54
+ should "have a create date/time" do
55
+ DateTime.expects(:parse).with('2008-07-28T16:57:10Z').returns('create_date')
56
+
57
+ @milestone.stubs(:created_timestamp).with().returns('2008-07-28T16:57:10Z')
58
+ @milestone.created_at.should == 'create_date'
59
+ end
60
+
61
+ should "have an update date/time" do
62
+ DateTime.expects(:parse).with('2009-04-28T18:48:52Z').returns('update_date')
63
+
64
+ @milestone.stubs(:updated_timestamp).with().returns('2009-04-28T18:48:52Z')
65
+ @milestone.updated_at.should == 'update_date'
66
+ end
67
+
68
+ should "have a due date" do
69
+ Date.expects(:parse).with('2008-07-30').returns('due_date')
70
+
71
+ @milestone.stubs(:due_datestamp).with().returns('2008-07-30')
72
+ @milestone.due_on.should == 'due_date'
73
+ end
74
+
75
+ should "not have a due date if there isn't one associated" do
76
+ @milestone.stubs(:due_datestamp).with().returns(nil)
77
+ @milestone.due_on.should be(nil)
78
+ end
79
+
80
+ should "have associated tickets" do
81
+ id = 1
82
+ project_id = 1
83
+
84
+ Ticket.expects(:find_all_by_project_id_and_milestone_id).with(project_id, id).returns('tickets')
85
+
86
+ @milestone.stubs(:id).with().returns(id)
87
+ @milestone.stubs(:project_id).with().returns(project_id)
88
+
89
+ @milestone.tickets.should == 'tickets'
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,107 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ module Unfuzzle
4
+ class ProjectTest < Test::Unit::TestCase
5
+
6
+ context "The Project class" do
7
+
8
+ should "be able to return a list of all projects" do
9
+ response = mock_request_cycle :for => '/projects', :data => 'projects'
10
+
11
+ elements = Array.new
12
+
13
+ response.data.each do |data|
14
+ element = stub()
15
+ Unfuzzle::Project.expects(:new).with(data).returns(element)
16
+ elements << element
17
+ end
18
+
19
+ Project.all.should == elements
20
+ end
21
+
22
+ should "be able to find a project by its slug" do
23
+ slug = 'blip'
24
+
25
+ response = mock_request_cycle :for => "/projects/by_short_name/#{slug}", :data => 'project'
26
+
27
+ Unfuzzle::Project.expects(:new).with(response.data).returns('project')
28
+
29
+ Project.find_by_slug(slug).should == 'project'
30
+ end
31
+
32
+ should "be able to find a project by its ID" do
33
+ id = 1
34
+
35
+ response = mock_request_cycle :for => "/projects/#{id}", :data => 'project'
36
+
37
+ Unfuzzle::Project.expects(:new).with(response.data).returns('project')
38
+
39
+ Project.find_by_id(id).should == 'project'
40
+ end
41
+
42
+
43
+ end
44
+
45
+ context "An instance of the Project class" do
46
+
47
+ when_populating Project, :from => 'projects' do
48
+
49
+ value_for :id, :is => 1
50
+ value_for :archived, :is => false
51
+ value_for :slug, :is => 'aa'
52
+ value_for :name, :is => 'A Client'
53
+ value_for :description, :is => 'A great project'
54
+ value_for :created_timestamp, :is => '2008-07-28T16:57:10Z'
55
+ value_for :updated_timestamp, :is => '2009-04-28T18:48:52Z'
56
+
57
+ end
58
+
59
+ context "with a new instance" do
60
+
61
+ setup { @project = Project.new(stub()) }
62
+
63
+ should "know that it's archived" do
64
+ @project.stubs(:archived).with().returns(true)
65
+ @project.archived?.should be(true)
66
+ end
67
+
68
+ should "know that it's not archived" do
69
+ @project.stubs(:archived).with().returns(false)
70
+ @project.archived?.should be(false)
71
+ end
72
+
73
+ should "have a create date" do
74
+ DateTime.expects(:parse).with('2008-07-28T16:57:10Z').returns('create_date')
75
+
76
+ @project.stubs(:created_timestamp).with().returns('2008-07-28T16:57:10Z')
77
+ @project.created_at.should == 'create_date'
78
+ end
79
+
80
+ should "have an update date" do
81
+ DateTime.expects(:parse).with('2009-04-28T18:48:52Z').returns('update_date')
82
+
83
+ @project.stubs(:updated_timestamp).with().returns('2009-04-28T18:48:52Z')
84
+ @project.updated_at.should == 'update_date'
85
+ end
86
+
87
+ should "have a list of associated milestones" do
88
+ id = 1
89
+ Milestone.expects(:find_all_by_project_id).with(id).returns('milestones')
90
+
91
+ @project.stubs(:id).with().returns(id)
92
+ @project.milestones.should == 'milestones'
93
+ end
94
+
95
+ should "have a list of associated tickets" do
96
+ id = 1
97
+ Ticket.expects(:find_all_by_project_id).with(id).returns('tickets')
98
+
99
+ @project.stubs(:id).with().returns(id)
100
+ @project.tickets.should == 'tickets'
101
+ end
102
+
103
+ end
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ module Unfuzzle
4
+ class RequestTest < Test::Unit::TestCase
5
+
6
+ context "The Request class" do
7
+
8
+ should "be able to perform a GET request" do
9
+ request = mock() {|r| r.expects(:get).with().returns('response') }
10
+ Unfuzzle::Request.expects(:new).with('/projects').returns(request)
11
+
12
+ Unfuzzle::Request.get('/projects').should == 'response'
13
+ end
14
+
15
+ end
16
+
17
+ context "An instance of the Request class" do
18
+
19
+ should "have an endpoint URI" do
20
+ Unfuzzle.stubs(:subdomain).with().returns('viget')
21
+
22
+ request = Unfuzzle::Request.new('/projects')
23
+ request.endpoint_uri.should == URI.parse('http://viget.unfuddle.com/api/v1/projects.json')
24
+ end
25
+
26
+ should "have a client" do
27
+ client = stub()
28
+
29
+ request = Unfuzzle::Request.new('/projects')
30
+ request.stubs(:endpoint_uri).with().returns(URI.parse('http://example.com'))
31
+
32
+ Net::HTTP.expects(:new).with('example.com').returns(client)
33
+
34
+ request.client.should == client
35
+ end
36
+
37
+ should "be able to perform a GET request" do
38
+ Unfuzzle.stubs(:username).with().returns('username')
39
+ Unfuzzle.stubs(:password).with().returns('password')
40
+
41
+ request = Unfuzzle::Request.new('/projects')
42
+ request.stubs(:endpoint_uri).returns(URI.parse('http://example.com/projects'))
43
+
44
+ get_request = mock() do |g|
45
+ g.expects(:basic_auth).with('username', 'password')
46
+ end
47
+
48
+ client = mock() {|c| c.expects(:request).with(get_request).returns('response') }
49
+
50
+ response = stub()
51
+ Unfuzzle::Response.expects(:new).with('response').returns(response)
52
+
53
+ Net::HTTP::Get.expects(:new).with('/projects').returns(get_request)
54
+
55
+ request.stubs(:client).with().returns(client)
56
+
57
+ request.get.should == response
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ module Unfuzzle
4
+ class ResponseTest < Test::Unit::TestCase
5
+
6
+ context "An instance of the Response class" do
7
+
8
+ should "delegate to the HTTP response to determine the body" do
9
+ http_response = mock() {|r| r.expects(:body).with().returns('check mah boday') }
10
+
11
+ response = Unfuzzle::Response.new(http_response)
12
+
13
+ response.body.should == 'check mah boday'
14
+ end
15
+
16
+ should "know that there are no errors" do
17
+ http_response = mock() do |r|
18
+ r.expects(:is_a?).with(Net::HTTPSuccess).returns(true)
19
+ end
20
+
21
+ response = Unfuzzle::Response.new(http_response)
22
+ response.error?.should be(false)
23
+ end
24
+
25
+ should "know if there are errors" do
26
+ http_response = mock() do |r|
27
+ r.expects(:is_a?).with(Net::HTTPSuccess).returns(false)
28
+ end
29
+
30
+ response = Unfuzzle::Response.new(http_response)
31
+ response.error?.should be(true)
32
+ end
33
+
34
+ should "be able to parse the response" do
35
+ response = Unfuzzle::Response.new(stub())
36
+ response.expects(:body).with().returns('json')
37
+ response.stubs(:error?).with().returns(false)
38
+
39
+ JSON.expects(:parse).with('json').returns('data')
40
+
41
+ response.data.should == 'data'
42
+ end
43
+
44
+ should "cache the parsed data from the response" do
45
+ response = Unfuzzle::Response.new(stub())
46
+ response.stubs(:body).with().returns('json')
47
+ response.stubs(:error?).with().returns(false)
48
+
49
+ JSON.stubs(:parse).with('json').once.returns('data')
50
+
51
+ 2.times { response.data }
52
+ end
53
+
54
+ should "return nil when parsing data if there are errors in the response" do
55
+ response = Unfuzzle::Response.new(stub())
56
+ response.expects(:error?).with().returns(true)
57
+
58
+ response.data.should be(nil)
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,92 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ module Unfuzzle
4
+ class TicketTest < Test::Unit::TestCase
5
+
6
+ context "The Ticket class" do
7
+
8
+ should "be able to return a list of tickets for a project" do
9
+ project_id = 1
10
+
11
+ response = mock_request_cycle :for => "/projects/#{project_id}/tickets", :data => 'tickets'
12
+
13
+ tickets = []
14
+
15
+ response.data.each do |data|
16
+ ticket = stub()
17
+ Ticket.expects(:new).with(data).returns(ticket)
18
+ tickets << ticket
19
+ end
20
+
21
+ Ticket.find_all_by_project_id(project_id).should == tickets
22
+ end
23
+
24
+ should "be able to return a list of tickets for a milestone" do
25
+ milestone_id = 1
26
+ project_id = 1
27
+
28
+ response = mock_request_cycle :for => "/projects/#{project_id}/milestones/#{milestone_id}/tickets", :data => 'tickets'
29
+
30
+ tickets = []
31
+
32
+ response.data.each do |data|
33
+ ticket = stub()
34
+ Ticket.expects(:new).with(data).returns(ticket)
35
+ tickets << ticket
36
+ end
37
+
38
+ Ticket.find_all_by_project_id_and_milestone_id(project_id, milestone_id).should == tickets
39
+ end
40
+
41
+ end
42
+
43
+ context "An instance of the Ticket class" do
44
+
45
+ when_populating Ticket, :from => 'tickets' do
46
+
47
+ value_for :id, :is => 1
48
+ value_for :created_timestamp, :is => '2008-11-25T14:00:19Z'
49
+ value_for :updated_timestamp, :is => '2008-12-31T15:51:41Z'
50
+ value_for :number, :is => 1
51
+ value_for :title, :is => 'Ticket #1'
52
+ value_for :description, :is => 'Do something important'
53
+ value_for :due_datestamp, :is => nil
54
+ value_for :status, :is => 'closed'
55
+
56
+ end
57
+
58
+ context "with a new instance" do
59
+ setup { @ticket = Ticket.new(stub()) }
60
+
61
+ should "have a create date/time" do
62
+ DateTime.expects(:parse).with('2008-07-28T16:57:10Z').returns('create_date')
63
+
64
+ @ticket.stubs(:created_timestamp).with().returns('2008-07-28T16:57:10Z')
65
+ @ticket.created_at.should == 'create_date'
66
+ end
67
+
68
+ should "have an update date/time" do
69
+ DateTime.expects(:parse).with('2009-04-28T18:48:52Z').returns('update_date')
70
+
71
+ @ticket.stubs(:updated_timestamp).with().returns('2009-04-28T18:48:52Z')
72
+ @ticket.updated_at.should == 'update_date'
73
+ end
74
+
75
+ should "have a due date" do
76
+ Date.expects(:parse).with('2008-07-30').returns('due_date')
77
+
78
+ @ticket.stubs(:due_datestamp).with().returns('2008-07-30')
79
+ @ticket.due_on.should == 'due_date'
80
+ end
81
+
82
+ should "not have a due date if there isn't one associated" do
83
+ @ticket.stubs(:due_datestamp).with().returns(nil)
84
+ @ticket.due_on.should be(nil)
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UnfuzzleTest < Test::Unit::TestCase
4
+
5
+ context "The Unfuzzle module" do
6
+
7
+ should "be able to set the subdomain" do
8
+ Unfuzzle.subdomain = 'viget'
9
+ Unfuzzle.subdomain.should == 'viget'
10
+ end
11
+
12
+ should "be able to set the username" do
13
+ Unfuzzle.username = 'username'
14
+ Unfuzzle.username.should == 'username'
15
+ end
16
+
17
+ should "be able to set the password" do
18
+ Unfuzzle.password = 'password'
19
+ Unfuzzle.password.should == 'password'
20
+ end
21
+
22
+ should "be able to retrieve a project by id" do
23
+ Unfuzzle::Project.expects(:find_by_id).with(1).returns('project')
24
+ Unfuzzle.project(1).should == 'project'
25
+ end
26
+
27
+ should "be able to retrieve a project by slug" do
28
+ Unfuzzle::Project.expects(:find_by_slug).with('slug').returns('project')
29
+ Unfuzzle.project('slug').should == 'project'
30
+ end
31
+
32
+ should "be able to retrieve a list of all projects for the current user" do
33
+ Unfuzzle::Project.expects(:all).with().returns('projects')
34
+ Unfuzzle.projects.should == 'projects'
35
+ end
36
+
37
+ end
38
+
39
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vigetlabs-unfuzzle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Patrick Reagan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-24 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.6
24
+ version:
25
+ description:
26
+ email: patrick.reagan@viget.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - README.rdoc
35
+ - Rakefile
36
+ - lib/unfuzzle
37
+ - lib/unfuzzle/milestone.rb
38
+ - lib/unfuzzle/model.rb
39
+ - lib/unfuzzle/project.rb
40
+ - lib/unfuzzle/request.rb
41
+ - lib/unfuzzle/response.rb
42
+ - lib/unfuzzle/ticket.rb
43
+ - lib/unfuzzle/version.rb
44
+ - lib/unfuzzle.rb
45
+ - test/fixtures
46
+ - test/fixtures/milestones.json
47
+ - test/fixtures/project.json
48
+ - test/fixtures/projects.json
49
+ - test/fixtures/tickets.json
50
+ - test/test_helper.rb
51
+ - test/unit
52
+ - test/unit/unfuzzle
53
+ - test/unit/unfuzzle/milestone_test.rb
54
+ - test/unit/unfuzzle/project_test.rb
55
+ - test/unit/unfuzzle/request_test.rb
56
+ - test/unit/unfuzzle/response_test.rb
57
+ - test/unit/unfuzzle/ticket_test.rb
58
+ - test/unit/unfuzzle_test.rb
59
+ has_rdoc: true
60
+ homepage: http://www.viget.com/extend
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --main
64
+ - README.rdoc
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: This gem provides an interface to the Unfuddle JSON API
86
+ test_files: []
87
+