timestamp_api 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +64 -11
- data/lib/timestamp_api/collection.rb +10 -0
- data/lib/timestamp_api/errors.rb +84 -1
- data/lib/timestamp_api/model.rb +31 -0
- data/lib/timestamp_api/model_attributes.rb +27 -0
- data/lib/timestamp_api/model_default_api_methods.rb +31 -0
- data/lib/timestamp_api/model_registry.rb +27 -0
- data/lib/timestamp_api/model_relations.rb +33 -0
- data/lib/timestamp_api/models/client.rb +7 -0
- data/lib/timestamp_api/models/project.rb +10 -0
- data/lib/timestamp_api/utils.rb +7 -0
- data/lib/timestamp_api/version.rb +1 -1
- data/lib/timestamp_api.rb +35 -13
- data/timestamp_api.gemspec +4 -2
- metadata +40 -4
- data/lib/timestamp_api/project.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a9b651bd6a1f81bb14b9edc23be1403ee37a4d3
|
4
|
+
data.tar.gz: 50238b9ee2ab12eb51b8fd4e5f82657c3cfb0385
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a72476235ef88e59f68f3e8d56a0d34c657581cf2f0cd4e2bbe626db7ec8d4193f89b5e90d45a14b7a299f326d431c93d204cd0d9ac4bfc9cd2ed974a46caa3
|
7
|
+
data.tar.gz: f6b28f91da78b36c7d8240fc1c37c5d16b21c2fac7242d4397fdcdb09cb87e0bf5773bcc60b4f46aa865333c337b7305ef3114277f72dce03f37942013e1d4c2
|
data/README.md
CHANGED
@@ -32,18 +32,72 @@ Configure your Timestamp API key by setting environment variable `TIMESTAMP_API_
|
|
32
32
|
TimestampAPi.api_key = "YOUR_TIMESTAMP_API_KEY"
|
33
33
|
```
|
34
34
|
|
35
|
+
#### Projects
|
36
|
+
|
35
37
|
List all projects:
|
36
38
|
```ruby
|
37
|
-
|
38
|
-
projects.map(&:name) # => ["A project", "Another project", "One more project"]
|
39
|
+
TimestampAPI::Project.all
|
39
40
|
```
|
40
41
|
|
41
42
|
Find a given project:
|
42
43
|
```ruby
|
43
|
-
project = TimestampAPI::Project.find(
|
44
|
+
project = TimestampAPI::Project.find(123)
|
45
|
+
|
46
|
+
project.name # => "My awesome project"
|
47
|
+
```
|
48
|
+
|
49
|
+
#### Clients
|
50
|
+
|
51
|
+
List all clients:
|
52
|
+
```ruby
|
53
|
+
TimestampAPI::Client.all
|
54
|
+
```
|
55
|
+
|
56
|
+
Find a given client:
|
57
|
+
```ruby
|
58
|
+
client = TimestampAPI::Client.find(123)
|
59
|
+
|
60
|
+
client.name # => "My beloved customer"
|
61
|
+
```
|
62
|
+
|
63
|
+
Find the client of a project
|
64
|
+
```ruby
|
65
|
+
project = TimestampAPI::Project.find(123)
|
66
|
+
|
44
67
|
project.client.name # => "My beloved customer"
|
45
68
|
```
|
46
69
|
|
70
|
+
## Models
|
71
|
+
|
72
|
+
The objects are represented by model classes (that inherits from `TimestampAPI::Model`):
|
73
|
+
```ruby
|
74
|
+
project = TimestampAPI::Project.find(123456)
|
75
|
+
|
76
|
+
project.class # => TimestampAPI::Project
|
77
|
+
project.is_a? TimestampAPI::Model # => true
|
78
|
+
```
|
79
|
+
|
80
|
+
Collections of objects are represented by `TimestampAPI::Collection` that inherits from `Array` (and implement the chainable `.where(conditions)` filter method described above). It means any `Array` method works on `TimestampAPI::Collection`:
|
81
|
+
```ruby
|
82
|
+
projects = TimestampAPI::Project.all
|
83
|
+
|
84
|
+
projects.class # => TimestampAPI::Collection
|
85
|
+
projects.map(&:name) # => ["A project", "Another project", "One more project"]
|
86
|
+
```
|
87
|
+
|
88
|
+
## Filtering
|
89
|
+
|
90
|
+
You can filter any object collection using the handy `.where()` syntax:
|
91
|
+
```ruby
|
92
|
+
projects = TimestampAPI::Project.all
|
93
|
+
|
94
|
+
projects.where(is_public: true) # => returns all public projects
|
95
|
+
projects.where(is_public: true, is_billable: true) # => returns all projects that are both public and billable
|
96
|
+
projects.where(is_public: true).where(is_billable: true) # => same as above: `where` is chainable \o/
|
97
|
+
```
|
98
|
+
|
99
|
+
:information_source: This does not filter objects **before** the network call (like ActiveRecord does), it's only a more elegant way of calling `Array#select` on the `Collection`
|
100
|
+
|
47
101
|
### Low level API calls
|
48
102
|
|
49
103
|
The above methods are simple wrappers around the generic low-level-ish API request method `TimestampAPI.request` that take a HTTP `method` (verb) and a `path` (to be appended to preconfigured API endpoint URL):
|
@@ -52,12 +106,9 @@ TimestampAPI.request(:get, "/projects") # Same as TimestampAPI::Project.a
|
|
52
106
|
TimestampAPI.request(:get, "/projects/123456") # Same as TimestampAPI::Project.find(123456)
|
53
107
|
```
|
54
108
|
|
55
|
-
|
109
|
+
To output all network requests done, you can set verbosity on:
|
56
110
|
```ruby
|
57
|
-
|
58
|
-
project.id # => 123456
|
59
|
-
project.name # => "Awesome project"
|
60
|
-
project.client.name # => "My beloved customer"
|
111
|
+
TimestampAPI.verbose = true
|
61
112
|
```
|
62
113
|
|
63
114
|
## Reverse engineering
|
@@ -74,12 +125,14 @@ There's also a `bin/console` executable provided with this gem, if you want a RE
|
|
74
125
|
|
75
126
|
### What's implemented already ?
|
76
127
|
|
77
|
-
* [x] Project#all
|
78
|
-
* [x] Project#find
|
128
|
+
* [x] `Project#all`
|
129
|
+
* [x] `Project#find`
|
130
|
+
* [x] `belongs_to` relationships
|
79
131
|
|
80
132
|
### What's not implemented yet ?
|
81
133
|
|
82
|
-
* [ ]
|
134
|
+
* [ ] _all other models_ :scream:
|
135
|
+
* [ ] `has_many` relationships
|
83
136
|
|
84
137
|
## Development
|
85
138
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
class Collection < Array
|
3
|
+
def where(conditions)
|
4
|
+
raise TimestampAPI::InvalidWhereContitions unless conditions.is_a? Hash
|
5
|
+
conditions.each_with_object(self.dup) do |condition, acc|
|
6
|
+
acc.select! { |i| i.send(condition.first.to_sym) == condition.last }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/timestamp_api/errors.rb
CHANGED
@@ -5,9 +5,92 @@ module TimestampAPI
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
class InvalidAPIKey < StandardError
|
9
|
+
def message
|
10
|
+
"Configured API key is invalid."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
class InvalidServerResponse < StandardError
|
9
15
|
def message
|
10
|
-
"Server responded with invalid JSON.
|
16
|
+
"Server responded with invalid JSON."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class InvalidModelData < StandardError
|
21
|
+
attr_reader :caller_class, :json_data
|
22
|
+
|
23
|
+
def initialize(caller_class, json_data)
|
24
|
+
@caller_class = caller_class
|
25
|
+
@json_data = json_data
|
26
|
+
end
|
27
|
+
|
28
|
+
def message
|
29
|
+
if json_data.is_a? Hash
|
30
|
+
"A `#{caller_class}` class was initialized with JSON data for a `#{json_data["object"] || "unknown"}` object."
|
31
|
+
else
|
32
|
+
"A `#{caller_class}` class was initialized with data which is not a `Hash` (it was a `#{json_data.class}`, actually)."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class UnknownModelData < StandardError
|
38
|
+
attr_reader :json_object
|
39
|
+
|
40
|
+
def initialize(json_object = nil)
|
41
|
+
@json_object = json_object
|
42
|
+
end
|
43
|
+
|
44
|
+
def message
|
45
|
+
if json_object
|
46
|
+
"JSON data with object type `#{json_object}` has no matching model implemented."
|
47
|
+
else
|
48
|
+
"JSON data doesn't have an `object` field or it's not valid JSON data."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class InvalidWhereContitions < StandardError
|
54
|
+
def message
|
55
|
+
"Conditions passed to `Collection#where` must be a hash."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class UnknownAssociation < StandardError
|
60
|
+
attr_reader :klass, :association_name
|
61
|
+
|
62
|
+
def initialize(klass, association_name)
|
63
|
+
@klass = klass
|
64
|
+
@association_name = association_name
|
65
|
+
end
|
66
|
+
|
67
|
+
def message
|
68
|
+
"Association `#{association_name}` could not be found on model `#{klass}`."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class ResourceNotFound < StandardError
|
73
|
+
attr_reader :klass, :id
|
74
|
+
|
75
|
+
def initialize(klass, id)
|
76
|
+
@klass = klass
|
77
|
+
@id = id
|
78
|
+
end
|
79
|
+
|
80
|
+
def message
|
81
|
+
"No `#{klass}` was found with id `#{id}` (API returned 404)"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class APIPathNotSet < StandardError
|
86
|
+
attr_reader :klass
|
87
|
+
|
88
|
+
def initialize(klass)
|
89
|
+
@klass = klass
|
90
|
+
end
|
91
|
+
|
92
|
+
def message
|
93
|
+
"API path not defined in `#{klass}` model. Use `api_path` to define it."
|
11
94
|
end
|
12
95
|
end
|
13
96
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
class Model
|
3
|
+
attr_reader :json_data
|
4
|
+
|
5
|
+
include Hooks
|
6
|
+
define_hooks :after_initialize, :after_inherited
|
7
|
+
|
8
|
+
include Utils
|
9
|
+
include ModelAttributes
|
10
|
+
include ModelRelations
|
11
|
+
include ModelDefaultAPIMethods
|
12
|
+
|
13
|
+
def self.inherited(subclass)
|
14
|
+
ModelRegistry.register(subclass)
|
15
|
+
run_hook :after_inherited, subclass
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(json_data)
|
19
|
+
@json_data = json_data
|
20
|
+
validate_init_data!
|
21
|
+
run_hook :after_initialize
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def validate_init_data!
|
27
|
+
class_basename = self.class.name.split("::").last
|
28
|
+
raise InvalidModelData.new(class_basename, json_data) unless json_data.is_a?(Hash) && json_data["object"] == class_basename.downcase
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
module ModelAttributes
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.class_eval do
|
6
|
+
after_initialize do
|
7
|
+
self.class.class_variable_get(:@@attributes).each do |attribute|
|
8
|
+
instance_variable_set(:"@#{attribute}", json_data[camelize(attribute)])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
after_inherited do |subclass|
|
13
|
+
subclass.class_variable_set(:@@attributes, [])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def has_attributes(*attributes)
|
20
|
+
# Add those attributes to the list of attributes for this class
|
21
|
+
self.class_variable_set(:@@attributes, self.class_variable_get(:@@attributes) + attributes)
|
22
|
+
# Define getters for those attributes
|
23
|
+
self.send(:attr_accessor, *attributes)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
module ModelDefaultAPIMethods
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.class_eval do
|
6
|
+
after_inherited do |subclass|
|
7
|
+
subclass.class_variable_set(:@@api_path, nil)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def api_path(path = nil)
|
14
|
+
path.nil? ? self.class_variable_get(:@@api_path) : self.class_variable_set(:@@api_path, path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def all
|
18
|
+
raise APIPathNotSet.new(self) if api_path.nil?
|
19
|
+
TimestampAPI.request(:get, api_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def find(id)
|
23
|
+
return nil if id.nil?
|
24
|
+
raise APIPathNotSet.new(self) if api_path.nil?
|
25
|
+
TimestampAPI.request(:get, "#{api_path}/#{id}")
|
26
|
+
rescue RestClient::ResourceNotFound
|
27
|
+
raise ResourceNotFound.new(self, id)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
class ModelRegistry
|
3
|
+
class << self
|
4
|
+
|
5
|
+
@@registry = {}
|
6
|
+
|
7
|
+
def register(klass)
|
8
|
+
@@registry[registry_key(klass)] = klass unless klass.name.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def registry
|
12
|
+
@@registry
|
13
|
+
end
|
14
|
+
|
15
|
+
def model_for(json_data)
|
16
|
+
raise UnknownModelData.new unless json_data.is_a? Hash
|
17
|
+
registry[json_data["object"]] || raise(UnknownModelData.new(json_data["object"]))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def registry_key(klass)
|
23
|
+
klass.name.split("::").last.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
module ModelRelations
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.class_eval do
|
6
|
+
after_initialize do
|
7
|
+
self.class.class_variable_get(:@@belongs_to).each do |association_name|
|
8
|
+
instance_variable_set(:"@_#{association_name}_id", json_data[camelize(association_name)]["id"]) if json_data.has_key? camelize(association_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
after_inherited do |subclass|
|
13
|
+
subclass.class_variable_set(:@@belongs_to, [])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def belongs_to(association_name)
|
20
|
+
# Add this association to the list of associations for this class
|
21
|
+
self.class_variable_set(:@@belongs_to, self.class_variable_get(:@@belongs_to) + [association_name])
|
22
|
+
# Define a memoizing getter for this association
|
23
|
+
define_method(association_name) do
|
24
|
+
return instance_variable_get(:"@#{association_name}") unless instance_variable_get(:"@#{association_name}").nil?
|
25
|
+
unknown_association_error = UnknownAssociation.new(self, association_name)
|
26
|
+
associationship_id = instance_variable_get(:"@_#{association_name}_id")
|
27
|
+
association_class = ModelRegistry.registry[association_name.to_s] || raise(unknown_association_error)
|
28
|
+
instance_variable_set(:"@#{association_name}", association_class.find(associationship_id))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module TimestampAPI
|
2
|
+
class Project < Model
|
3
|
+
api_path "/projects"
|
4
|
+
|
5
|
+
has_attributes :id, :created_at, :updated_at, :account_id, :name, :code, :color, :initiation_date,
|
6
|
+
:target_completion_date, :is_archived, :is_billable, :is_public, :is_approvable
|
7
|
+
|
8
|
+
belongs_to :client
|
9
|
+
end
|
10
|
+
end
|
data/lib/timestamp_api.rb
CHANGED
@@ -1,41 +1,63 @@
|
|
1
1
|
require "rest-client"
|
2
|
-
require "
|
2
|
+
require "colorize"
|
3
|
+
require "hooks"
|
3
4
|
|
4
5
|
require "timestamp_api/version"
|
5
6
|
require "timestamp_api/errors"
|
6
|
-
require "timestamp_api/
|
7
|
+
require "timestamp_api/utils"
|
8
|
+
require "timestamp_api/model_registry"
|
9
|
+
require "timestamp_api/model_attributes"
|
10
|
+
require "timestamp_api/model_relations"
|
11
|
+
require "timestamp_api/model_default_api_methods"
|
12
|
+
require "timestamp_api/model"
|
13
|
+
require "timestamp_api/collection"
|
14
|
+
require "timestamp_api/models/project"
|
15
|
+
require "timestamp_api/models/client"
|
7
16
|
|
8
17
|
module TimestampAPI
|
9
18
|
@api_endpoint = "https://api.ontimestamp.com/api"
|
10
19
|
|
11
20
|
class << self
|
12
|
-
attr_accessor :api_endpoint, :api_key
|
21
|
+
attr_accessor :api_endpoint, :api_key, :verbose
|
13
22
|
end
|
14
23
|
|
15
|
-
def self.request(method,
|
16
|
-
|
17
|
-
|
24
|
+
def self.request(method, path, query_params = {})
|
25
|
+
output(method, path, query_params) if verbose
|
26
|
+
response = RestClient::Request.execute(request_options(method, path, query_params))
|
27
|
+
modelify(JSON.parse(response))
|
28
|
+
rescue RestClient::Forbidden
|
29
|
+
raise InvalidAPIKey
|
18
30
|
rescue JSON::ParserError
|
19
31
|
raise InvalidServerResponse
|
20
32
|
end
|
21
33
|
|
22
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
def self.request_options(method, path, query_params)
|
23
37
|
{
|
24
38
|
method: method,
|
25
|
-
url: api_endpoint +
|
39
|
+
url: api_endpoint + path,
|
26
40
|
headers: {
|
27
41
|
"X-API-Key" => api_key || ENV["TIMESTAMP_API_KEY"] || raise(MissingAPIKey),
|
28
42
|
:accept => :json,
|
29
|
-
:user_agent => "TimestampAPI Ruby gem https://github.com/alpinelab/timestamp_api"
|
43
|
+
:user_agent => "TimestampAPI Ruby gem (https://github.com/alpinelab/timestamp_api)",
|
44
|
+
:params => query_params
|
30
45
|
}
|
31
46
|
}
|
32
47
|
end
|
33
48
|
|
34
|
-
def self.
|
49
|
+
def self.modelify(json)
|
35
50
|
case json
|
36
|
-
when Array then json.map { |item|
|
37
|
-
when Hash then
|
38
|
-
else json
|
51
|
+
when Array then Collection.new(json.map { |item| modelify(item) })
|
52
|
+
when Hash then ModelRegistry.model_for(json).new(json)
|
39
53
|
end
|
40
54
|
end
|
55
|
+
|
56
|
+
def self.output(method, path, query_params)
|
57
|
+
print "TimestampAPI ".colorize(:red)
|
58
|
+
print "#{method.upcase} ".colorize(:yellow)
|
59
|
+
full_path = path
|
60
|
+
full_path += "?#{query_params.each_with_object([]) { |p, acc| acc << "#{p[0]}=#{p[1]}" }.join("&")}" unless query_params.empty?
|
61
|
+
puts full_path.colorize(:yellow)
|
62
|
+
end
|
41
63
|
end
|
data/timestamp_api.gemspec
CHANGED
@@ -19,12 +19,14 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_runtime_dependency "rest-client"
|
23
|
-
spec.add_runtime_dependency "
|
22
|
+
spec.add_runtime_dependency "rest-client", ">= 1.7.3"
|
23
|
+
spec.add_runtime_dependency "colorize"
|
24
|
+
spec.add_runtime_dependency "hooks"
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.9"
|
26
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
28
|
spec.add_development_dependency "rspec"
|
28
29
|
spec.add_development_dependency "pry"
|
29
30
|
spec.add_development_dependency "awesome_print"
|
31
|
+
spec.add_development_dependency "webmock", "~> 1.22"
|
30
32
|
end
|
metadata
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timestamp_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Baudino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colorize
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - ">="
|
@@ -25,7 +39,7 @@ dependencies:
|
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: hooks
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.22'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.22'
|
111
139
|
description: 'Timestamp is "real-time project tracking for you and your clients" according
|
112
140
|
to their website: https://www.timestamphq.com'
|
113
141
|
email:
|
@@ -129,8 +157,16 @@ files:
|
|
129
157
|
- bin/console
|
130
158
|
- bin/setup
|
131
159
|
- lib/timestamp_api.rb
|
160
|
+
- lib/timestamp_api/collection.rb
|
132
161
|
- lib/timestamp_api/errors.rb
|
133
|
-
- lib/timestamp_api/
|
162
|
+
- lib/timestamp_api/model.rb
|
163
|
+
- lib/timestamp_api/model_attributes.rb
|
164
|
+
- lib/timestamp_api/model_default_api_methods.rb
|
165
|
+
- lib/timestamp_api/model_registry.rb
|
166
|
+
- lib/timestamp_api/model_relations.rb
|
167
|
+
- lib/timestamp_api/models/client.rb
|
168
|
+
- lib/timestamp_api/models/project.rb
|
169
|
+
- lib/timestamp_api/utils.rb
|
134
170
|
- lib/timestamp_api/version.rb
|
135
171
|
- timestamp_api.gemspec
|
136
172
|
homepage: https://github.com/alpinelab/timestamp_api
|