tickspot 0.1.0
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/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.textile +3 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/tickspot.rb +146 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/tickspot_spec.rb +188 -0
- data/tickspot.gemspec +56 -0
- metadata +85 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jeff Kreeftmeijer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "tickspot"
|
8
|
+
gem.summary = %Q{The Tickspot Ruby API wrapper.}
|
9
|
+
gem.description = %Q{The Tickspot Ruby API wrapper.}
|
10
|
+
gem.email = "jeff@kreeftmeijer.nl"
|
11
|
+
gem.homepage = "http://github.com/jeffkreeftmeijer/tickspot"
|
12
|
+
gem.authors = ["Jeff Kreeftmeijer"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
gem.add_development_dependency "yard"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
begin
|
38
|
+
require 'yard'
|
39
|
+
YARD::Rake::YardocTask.new
|
40
|
+
rescue LoadError
|
41
|
+
task :yardoc do
|
42
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Jeweler::GemcutterTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/tickspot.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
module Tickspot
|
5
|
+
class << self
|
6
|
+
attr_accessor :company, :email, :password
|
7
|
+
end
|
8
|
+
|
9
|
+
class Request
|
10
|
+
|
11
|
+
##
|
12
|
+
# Send a post request to Tickspot. Will use Tickspot.company and
|
13
|
+
# Tickspot.section to build the url and passes every op tion it received (
|
14
|
+
# merged with Tickspot.email and Tickspot.password ) to HTTParty's :query
|
15
|
+
# parameter. It'll return everythin within the returned root node ( which
|
16
|
+
# is named equally to the section name ).
|
17
|
+
#
|
18
|
+
# @param [Hash] options The options you want to pass.
|
19
|
+
#
|
20
|
+
# @return [Array] items An array of hashes with the item data.
|
21
|
+
|
22
|
+
def self.post(options)
|
23
|
+
section = options.delete(:section)
|
24
|
+
result = HTTParty.post(
|
25
|
+
"https://#{Tickspot.company}.tickspot.com/api/#{section}",
|
26
|
+
:query => options.merge({
|
27
|
+
:email => Tickspot.email,
|
28
|
+
:password => Tickspot.password
|
29
|
+
})
|
30
|
+
)
|
31
|
+
result[section.to_s]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Base
|
36
|
+
attr_reader :attributes
|
37
|
+
|
38
|
+
##
|
39
|
+
# Create a new Tickspot::Base object. Will put the data provided in
|
40
|
+
# the @attributes attribute.
|
41
|
+
#
|
42
|
+
# @param [Hash] data The item's data.
|
43
|
+
#
|
44
|
+
# @return [Tickspot::Base] object The created object.
|
45
|
+
|
46
|
+
def initialize(data)
|
47
|
+
@attributes = data
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Fetch the missing methods. Will fetch all missing methods executed on a
|
52
|
+
# Tickspot::Base object and use the method_id as a key to find a value in
|
53
|
+
# the object's @attributes. If the value found is an Array, it'll create a
|
54
|
+
# wrap it into a new object using the name to determine which one.
|
55
|
+
#
|
56
|
+
# @param [symbol] method_id The name of the missing method.
|
57
|
+
# @param [*] *args Additional arguments.
|
58
|
+
#
|
59
|
+
# @return [*] value The found value.
|
60
|
+
|
61
|
+
def method_missing(method_id, *args)
|
62
|
+
value = @attributes[method_id.to_s]
|
63
|
+
if value.is_a? Array
|
64
|
+
return value.map do |item|
|
65
|
+
self.class.sections.index(method_id).new(item)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
value
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# The item id. Will return @attributes['id']
|
73
|
+
#
|
74
|
+
# @return [Integer] id The item id
|
75
|
+
|
76
|
+
def id
|
77
|
+
@attributes['id']
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# The object section. Needs to be called by an extending class. Will get
|
82
|
+
# the section (to be passed to Tickspot in the url) from self.sections
|
83
|
+
# using the constant name.
|
84
|
+
#
|
85
|
+
# @return [Symbol] section The object section
|
86
|
+
|
87
|
+
def self.section
|
88
|
+
sections[self]
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Fetch all items and return them in an array of objects. Will get the
|
93
|
+
# section using self.section (so Tickspot::Base needs to be extended) and
|
94
|
+
# merge that with any passed arguments to pass to Request.post. Every hash
|
95
|
+
# in the returned array will get wrapped in an item object.
|
96
|
+
#
|
97
|
+
# @return [Array] items An array of item objects.
|
98
|
+
|
99
|
+
def self.all(options = {})
|
100
|
+
result = Request.post(
|
101
|
+
options.merge({
|
102
|
+
:section => section
|
103
|
+
})
|
104
|
+
)
|
105
|
+
result.map{|item| new(item)} if result
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# The list to convert constant names to section symbols.
|
110
|
+
#
|
111
|
+
# @return [Hash] sections The list of sections.
|
112
|
+
|
113
|
+
def self.sections
|
114
|
+
{
|
115
|
+
Tickspot::Client => :clients,
|
116
|
+
Tickspot::Project => :projects,
|
117
|
+
Tickspot::Task => :tasks,
|
118
|
+
Tickspot::ClientProjectTask => :clients_projects_tasks,
|
119
|
+
Tickspot::Entry => :entries,
|
120
|
+
Tickspot::RecentTask => :recent_tasks,
|
121
|
+
Tickspot::User => :users,
|
122
|
+
Tickspot::CreateEntry => :create_entry,
|
123
|
+
Tickspot::UpdateEntry => :update_entry
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Client < Base; end
|
129
|
+
|
130
|
+
class Project < Base; end
|
131
|
+
|
132
|
+
class Task < Base; end
|
133
|
+
|
134
|
+
class ClientProjectTask < Base; end
|
135
|
+
|
136
|
+
class Entry < Base; end
|
137
|
+
|
138
|
+
class RecentTask < Base; end
|
139
|
+
|
140
|
+
class User < Base; end
|
141
|
+
|
142
|
+
class CreateEntry < Base; end
|
143
|
+
|
144
|
+
class UpdateEntry < Base; end
|
145
|
+
|
146
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Tickspot do
|
4
|
+
it 'should set the company' do
|
5
|
+
Tickspot.company = 'c0mp4ny'
|
6
|
+
Tickspot.company.should == 'c0mp4ny'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should set the email' do
|
10
|
+
Tickspot.email = 'my@email.com'
|
11
|
+
Tickspot.email.should == 'my@email.com'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should set the password' do
|
15
|
+
Tickspot.password = 'secret'
|
16
|
+
Tickspot.password.should == 'secret'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Tickspot::Request do
|
21
|
+
describe '.post' do
|
22
|
+
before do
|
23
|
+
@result = {'tests' => []}
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should do a post request with the parameters' do
|
27
|
+
HTTParty.should_receive(:post).with(
|
28
|
+
'https://c0mp4ny.tickspot.com/api/tests',
|
29
|
+
:query => {
|
30
|
+
:email => 'my@email.com',
|
31
|
+
:password => 'secret'
|
32
|
+
}
|
33
|
+
).and_return(@result)
|
34
|
+
|
35
|
+
Tickspot::Request.post(
|
36
|
+
:section => :tests
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should pass every argument in the query hash' do
|
41
|
+
HTTParty.should_receive(:post).with(
|
42
|
+
'https://c0mp4ny.tickspot.com/api/tests',
|
43
|
+
:query => {
|
44
|
+
:email => 'my@email.com',
|
45
|
+
:password => 'secret',
|
46
|
+
:woo => 'bleh'
|
47
|
+
}
|
48
|
+
).and_return(@result)
|
49
|
+
|
50
|
+
Tickspot::Request.post(
|
51
|
+
:section => :tests,
|
52
|
+
:woo => 'bleh'
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should strip the top level node' do
|
57
|
+
HTTParty.stub!(:post).and_return(@result)
|
58
|
+
|
59
|
+
Tickspot::Request.post(
|
60
|
+
:section => :tests
|
61
|
+
).should == []
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe Tickspot::Base do
|
67
|
+
before do
|
68
|
+
class BaseTest < Tickspot::Base
|
69
|
+
def self.section
|
70
|
+
:tests
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
@test = BaseTest.new({'id' => 14, 'name' => 'test!'})
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#new' do
|
78
|
+
it 'should set the attributes' do
|
79
|
+
@test.attributes.should == {'id' => 14, 'name' => 'test!'}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#method_missing' do
|
84
|
+
it 'should find the attribute' do
|
85
|
+
@test.name.should == 'test!'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should turn nested hashes into objects' do
|
89
|
+
test = BaseTest.new({
|
90
|
+
'id' => 14,
|
91
|
+
'name' => 'test!',
|
92
|
+
'clients' => [
|
93
|
+
{
|
94
|
+
'id' => 15,
|
95
|
+
'name' => 'nested'
|
96
|
+
}
|
97
|
+
]
|
98
|
+
})
|
99
|
+
test.clients.should be_instance_of Array
|
100
|
+
test.clients.length.should == 1
|
101
|
+
test.clients.each do |client|
|
102
|
+
client.should be_instance_of Tickspot::Client
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#id' do
|
108
|
+
it 'should return the "id" attribute' do
|
109
|
+
@test.id.should == 14
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '.all' do
|
114
|
+
it 'should send a request' do
|
115
|
+
Tickspot::Request.should_receive(:post).with(
|
116
|
+
:section => :tests
|
117
|
+
)
|
118
|
+
BaseTest.all
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should pass the arguments' do
|
122
|
+
Tickspot::Request.should_receive(:post).with(
|
123
|
+
:section => :tests,
|
124
|
+
:project_id => 14
|
125
|
+
)
|
126
|
+
BaseTest.all(:project_id => 14)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should return BaseTest objects' do
|
130
|
+
Tickspot::Request.stub!(:post).and_return([{:id => 123}])
|
131
|
+
BaseTest.all.first.should be_instance_of BaseTest
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe Tickspot::Client do
|
137
|
+
it 'should have :clients as its section' do
|
138
|
+
Tickspot::Client.section.should == :clients
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe Tickspot::Project do
|
143
|
+
it 'should have :projects as its section' do
|
144
|
+
Tickspot::Project.section.should == :projects
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe Tickspot::Task do
|
149
|
+
it 'should have :tasks as its section' do
|
150
|
+
Tickspot::Task.section.should == :tasks
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe Tickspot::ClientProjectTask do
|
155
|
+
it 'should have :clients_projects_tasks as its section' do
|
156
|
+
Tickspot::ClientProjectTask.section.should == :clients_projects_tasks
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe Tickspot::Entry do
|
161
|
+
it 'should have :entries as its section' do
|
162
|
+
Tickspot::Entry.section.should == :entries
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe Tickspot::RecentTask do
|
167
|
+
it 'should have :recent_tasks as its section' do
|
168
|
+
Tickspot::RecentTask.section.should == :recent_tasks
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe Tickspot::User do
|
173
|
+
it 'should have :users as its section' do
|
174
|
+
Tickspot::User.section.should == :users
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe Tickspot::CreateEntry do
|
179
|
+
it 'should have :create_entry as its section' do
|
180
|
+
Tickspot::CreateEntry.section.should == :create_entry
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe Tickspot::UpdateEntry do
|
185
|
+
it 'should have :update_entry as its section' do
|
186
|
+
Tickspot::UpdateEntry.section.should == :update_entry
|
187
|
+
end
|
188
|
+
end
|
data/tickspot.gemspec
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{tickspot}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jeff Kreeftmeijer"]
|
12
|
+
s.date = %q{2010-02-09}
|
13
|
+
s.description = %q{The Tickspot Ruby API wrapper.}
|
14
|
+
s.email = %q{jeff@kreeftmeijer.nl}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.textile"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.textile",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/tickspot.rb",
|
27
|
+
"spec/spec_helper.rb",
|
28
|
+
"spec/tickspot_spec.rb",
|
29
|
+
"tickspot.gemspec"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/jeffkreeftmeijer/tickspot}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.5}
|
35
|
+
s.summary = %q{The Tickspot Ruby API wrapper.}
|
36
|
+
s.test_files = [
|
37
|
+
"spec/spec_helper.rb",
|
38
|
+
"spec/tickspot_spec.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
50
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
51
|
+
end
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
54
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tickspot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Kreeftmeijer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-09 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yard
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: The Tickspot Ruby API wrapper.
|
36
|
+
email: jeff@kreeftmeijer.nl
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.textile
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.textile
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- lib/tickspot.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
- spec/tickspot_spec.rb
|
54
|
+
- tickspot.gemspec
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/jeffkreeftmeijer/tickspot
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --charset=UTF-8
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
requirements: []
|
77
|
+
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.3.5
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: The Tickspot Ruby API wrapper.
|
83
|
+
test_files:
|
84
|
+
- spec/spec_helper.rb
|
85
|
+
- spec/tickspot_spec.rb
|