forecasting 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edb8ec26fd106cae648d103e0d55a3eac43a84950932903c964263597641dae1
4
- data.tar.gz: cc0ff4974048deca834309b5c652bd776ba6ef78454f7cf5cbe1afeeb85dc4cf
3
+ metadata.gz: 28606e4981727f588e0ab9a027bcea84cd3f25563d2ab031b2eeb075455d42be
4
+ data.tar.gz: e68359ad5b0452f3c60f5d5d4c00a7cf9f03311da0d277b7832c88a3115dfc68
5
5
  SHA512:
6
- metadata.gz: bf01d135878f0a0fe617787f0b4f73404b5cbc71b0fe6ea7c460b47bb8e097f25265925d9a50e78dc5bd17386d32773d8e86428ed2ad414e293d2b1975296f5a
7
- data.tar.gz: f58e4883da565c2388e6baa5b6b09498574e5e214cbc21d1e0cff0b9d696462db230c07b3406500ee6583faa5f680960bc78670a66570805d688fb4fd3b080f1
6
+ metadata.gz: 37dccf7bdca14315ec3810be2bc6de1123827b5388a903dee7b5f2f9501a064c3772a10afc0cb5fa5dee12c7da0335b9f7e82a80927052c8f20376f4fdb233d9
7
+ data.tar.gz: da4002bc71187fe2084fee8c377de963805f93a7ba79e0a7489cd6f275ff8985b688ca805823282da145334cdd0684eb113ffb8e9e0c1f553e6bb40cdfae937e
data/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  **Bug Fixes**
6
6
 
7
+ ## Version 0.2.0 - Jan 30, 2023
8
+
9
+ **Notes**
10
+
11
+ - Refactored Forecasting::Models::Base and Forecasting::Models::ForecastRecord
12
+
7
13
  ## Version 0.1.0 - Jan 29, 2023
8
14
 
9
15
  **Notes**
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/forecasting.svg)](https://badge.fury.io/rb/forecasting)
4
4
  [![Tests](https://github.com/NeomindLabs/forecasting/actions/workflows/ruby.yml/badge.svg)](https://github.com/NeomindLabs/forecasting/actions/workflows/ruby.yml)
5
- [![Code Climate](https://codeclimate.com/github/NeomindLabs/forecasting/badges/gpa.svg)](https://codeclimate.com/github/NeomindLabs/forecasting)
6
5
 
7
6
  A Ruby gem to interact with the Harvest Forecast API. Please note that there is currently [no official public API](https://help.getharvest.com/forecast/faqs/faq-list/api). This API client has been made by inspecting network requests using the Forecast website. This library is based on the excellent [Harvesting](https://github.com/fastruby/harvesting) gem.
8
7
 
@@ -17,12 +17,12 @@ class Forecasting::Client
17
17
 
18
18
  # @return [Forecasting::Models::Account]
19
19
  def account(id:)
20
- Forecasting::Models::Account.new(get("accounts/#{id}")["account"])
20
+ Forecasting::Models::Account.new(get("accounts/#{id}")["account"], forecast_client: self)
21
21
  end
22
22
 
23
23
  # @return [Forecasting::Models::Assignment]
24
24
  def assignment(id:)
25
- Forecasting::Models::Assignment.new(get("assignments/#{id}")["assignment"], forecast_client: self)
25
+ Forecasting::Models::Assignment.get(id, forecast_client: self)
26
26
  end
27
27
 
28
28
  # @return [Array<Forecasting::Models::Assignment>]
@@ -34,7 +34,7 @@ class Forecasting::Client
34
34
 
35
35
  # @return [Forecasting::Models::Client]
36
36
  def client(id:)
37
- Forecasting::Models::Client.new(get("clients/#{id}")["client"], forecast_client: self)
37
+ Forecasting::Models::Client.get(id, forecast_client: self)
38
38
  end
39
39
 
40
40
  # @return [Array<Forecasting::Models::Client>]
@@ -46,7 +46,7 @@ class Forecasting::Client
46
46
 
47
47
  # @return [Forecasting::Models::FtuxState]
48
48
  def ftux_state
49
- Forecasting::Models::FtuxState.new(get("ftux_state")["ftux_state"])
49
+ Forecasting::Models::FtuxState.new(get("ftux_state")["ftux_state"], forecast_client: self)
50
50
  end
51
51
 
52
52
  # @return [Array<Forecasting::Models::FutureScheduledHours>]
@@ -59,7 +59,7 @@ class Forecasting::Client
59
59
 
60
60
  # @return [Forecasting::Models::Milestone]
61
61
  def milestone(id:)
62
- Forecasting::Models::Milestone.new(get("milestones/#{id}")["milestone"], forecast_client: self)
62
+ Forecasting::Models::Milestone.get(id, forecast_client: self)
63
63
  end
64
64
 
65
65
  # @return [Array<Forecasting::Models::Milestone>]
@@ -71,7 +71,7 @@ class Forecasting::Client
71
71
 
72
72
  # @return [Forecasting::Models::Person]
73
73
  def person(id:)
74
- Forecasting::Models::Person.new(get("people/#{id}")["person"], forecast_client: self)
74
+ Forecasting::Models::Person.get(id, forecast_client: self)
75
75
  end
76
76
 
77
77
  # @return [Array<Forecasting::Models::Person>]
@@ -83,7 +83,7 @@ class Forecasting::Client
83
83
 
84
84
  # @return [Forecasting::Models::Placeholder]
85
85
  def placeholder(id:)
86
- Forecasting::Models::Placeholder.new(get("placeholders/#{id}")["placeholder"], forecast_client: self)
86
+ Forecasting::Models::Placeholder.get(id, forecast_client: self)
87
87
  end
88
88
 
89
89
  # @return [Array<Forecasting::Models::Placeholder>]
@@ -95,7 +95,7 @@ class Forecasting::Client
95
95
 
96
96
  # @return [Forecasting::Models::Projects]
97
97
  def project(id:)
98
- Forecasting::Models::Project.new(get("projects/#{id}")["project"], forecast_client: self)
98
+ Forecasting::Models::Project.get(id, forecast_client: self)
99
99
  end
100
100
 
101
101
  # @return [Array<Forecasting::Models::Project>]
@@ -114,7 +114,7 @@ class Forecasting::Client
114
114
 
115
115
  # @return [Forecasting::Models::RepeatedAssignmentSet]
116
116
  def repeated_assignment_set(id:)
117
- Forecasting::Models::RepeatedAssignmentSet.new(get("repeated_assignment_sets/#{id}")["repeated_assignment_set"], forecast_client: self)
117
+ Forecasting::Models::RepeatedAssignmentSet.get(id, forecast_client: self)
118
118
  end
119
119
 
120
120
  # @return [Array<Forecasting::Models::RepeatedAssignmentSet>]
@@ -126,7 +126,7 @@ class Forecasting::Client
126
126
 
127
127
  # @return [Forecasting::Models::Role]
128
128
  def role(id:)
129
- Forecasting::Models::Role.new(get("roles/#{id}")["role"], forecast_client: self)
129
+ Forecasting::Models::Role.get(id, forecast_client: self)
130
130
  end
131
131
 
132
132
  # @return [Array<Forecasting::Models::Role>]
@@ -138,19 +138,19 @@ class Forecasting::Client
138
138
 
139
139
  # @return [Forecasting::Models::Subscription]
140
140
  def subscription
141
- Forecasting::Models::Subscription.new(get("billing/subscription")["subscription"])
141
+ Forecasting::Models::Subscription.new(get("billing/subscription")["subscription"], forecast_client: self)
142
142
  end
143
143
 
144
144
  # @return [Forecasting::Models::UserConnection]
145
145
  def user_connections(opts = {})
146
146
  get("user_connections", opts)["user_connections"].map do |entry|
147
- Forecasting::Models::UserConnection.new(entry)
147
+ Forecasting::Models::UserConnection.new(entry, forecast_client: self)
148
148
  end
149
149
  end
150
150
 
151
151
  # @return [Forecasting::Models::User]
152
152
  def whoami
153
- Forecasting::Models::User.new(get("whoami")["current_user"])
153
+ Forecasting::Models::User.new(get("whoami")["current_user"], forecast_client: self)
154
154
  end
155
155
 
156
156
  # Creates an `entity` in your Harvest account.
@@ -13,4 +13,7 @@ module Forecasting
13
13
 
14
14
  class RateLimitExceeded < StandardError
15
15
  end
16
+
17
+ class MethodNotImplemented < StandardError
18
+ end
16
19
  end
@@ -15,7 +15,7 @@ module Forecasting
15
15
  :updated_by_id
16
16
 
17
17
  def path
18
- @attributes['id'].nil? ? "milestones" : "milestones/#{@attributes['id']}"
18
+ @attributes['id'].nil? ? "assignments" : "assignments/#{@attributes['id']}"
19
19
  end
20
20
 
21
21
  def project
@@ -1,10 +1,14 @@
1
1
  module Forecasting
2
2
  module Models
3
3
  class Base
4
+ # @return [Forecasting::Client]
5
+ attr_reader :forecast_client
6
+
4
7
  # @return [Hash]
5
8
  attr_accessor :attributes
6
9
 
7
- def initialize(attrs)
10
+ def initialize(attrs, opts = {})
11
+ @forecast_client = opts[:forecast_client] || Forecasting::Client.new(**opts)
8
12
  @attributes = attrs.dup
9
13
  @models = {}
10
14
  end
@@ -16,7 +20,6 @@ module Forecasting
16
20
  @attributes
17
21
  end
18
22
 
19
-
20
23
  # Class method to define attribute methods for accessing attributes for
21
24
  # a record
22
25
  #
@@ -55,7 +58,7 @@ module Forecasting
55
58
  opts.each do |attribute_name, model|
56
59
  attribute_name_string = attribute_name.to_s
57
60
  define_method(attribute_name_string) do
58
- @models[attribute_name_string] ||= model.new(@attributes[attribute_name_string] || {})
61
+ @models[attribute_name_string] ||= model.new(@attributes[attribute_name_string] || {}, forecast_client: forecast_client)
59
62
  end
60
63
  end
61
64
  end
@@ -1,13 +1,6 @@
1
1
  module Forecasting
2
2
  module Models
3
3
  class ForecastRecord < Base
4
- # @return [Forecasting::Model::Client]
5
- attr_reader :forecast_client
6
-
7
- def initialize(attrs, opts = {})
8
- @forecast_client = opts[:forecast_client] || Forecasting::Client.new(**opts)
9
- super(attrs)
10
- end
11
4
 
12
5
  def save
13
6
  id.nil? ? create : update
@@ -25,11 +18,10 @@ module Forecasting
25
18
  forecast_client.delete(self)
26
19
  end
27
20
 
28
- # It loads a new record from your Harvest account.
29
- #
30
- # @return [Forecasting::Models::Base]
21
+ # It loads a new record from your Harvest account. #
22
+ # @return [Forecasting::Models::ForecastRecord]
31
23
  def fetch
32
- self.class.new(@forecast_client.get(path), forecast_client: @forecast_client)
24
+ self.class.new(forecast_client.get(path), forecast_client: forecast_client)
33
25
  end
34
26
 
35
27
  # It returns the model type
@@ -39,6 +31,10 @@ module Forecasting
39
31
  self.class.name.split("::").last.downcase
40
32
  end
41
33
 
34
+ def path
35
+ raise Forecasting::MethodNotImplemented
36
+ end
37
+
42
38
  # Retrieves an instance of the object by ID
43
39
  #
44
40
  # @param id [Integer] the id of the object to retrieve
@@ -46,27 +42,8 @@ module Forecasting
46
42
  # instance
47
43
  def self.get(id, opts = {})
48
44
  client = opts[:forecast_client] || Forecasting::Client.new(**opts)
49
- self.new({ 'id' => id }, opts).fetch
50
- end
51
-
52
- protected
53
-
54
- # Class method to define nested resources for a record.
55
- #
56
- # It needs to be used like this:
57
- #
58
- # class Project < ForecastRecord
59
- # modeled client: Client
60
- # ...
61
- # end
62
- #
63
- # @param opts [Hash] key = symbol that needs to be the same as the one returned by the Harvest API. value = model class for the nested resource.
64
- def self.modeled(opts = {})
65
- opts.each do |attribute_name, model|
66
- attribute_name_string = attribute_name.to_s
67
- define_method(attribute_name_string) do
68
- @models[attribute_name_string] ||= model.new(@attributes[attribute_name_string] || {}, forecast_client: forecast_client)
69
- end
45
+ self.new({ 'id' => id }, opts).tap do |record|
46
+ record.attributes = client.get(record.path)
70
47
  end
71
48
  end
72
49
  end
@@ -1,19 +1,11 @@
1
1
  module Forecasting
2
2
  module Models
3
3
  class FutureScheduledHours < Base
4
- # @return [Forecasting::Model::Client]
5
- attr_reader :forecast_client
6
-
7
4
  attributed :project_id,
8
5
  :person_id,
9
6
  :placeholder_id,
10
7
  :allocation
11
8
 
12
- def initialize(attrs, opts = {})
13
- @forecast_client = opts[:forecast_client] || Forecasting::Client.new(**opts)
14
- super(attrs)
15
- end
16
-
17
9
  def project
18
10
  forecast_client.project(id: project_id)
19
11
  end
@@ -1,20 +1,12 @@
1
1
  module Forecasting
2
2
  module Models
3
3
  class RemainingBudgetedHours < Base
4
- # @return [Forecasting::Model::Client]
5
- attr_reader :forecast_client
6
-
7
4
  attributed :project_id,
8
5
  :budget_by,
9
6
  :budget_is_monthly,
10
7
  :hours,
11
8
  :response_code
12
9
 
13
- def initialize(attrs, opts = {})
14
- @forecast_client = opts[:forecast_client] || Forecasting::Client.new(**opts)
15
- super(attrs)
16
- end
17
-
18
10
  def project
19
11
  forecast_client.project(id: project_id)
20
12
  end
@@ -1,3 +1,3 @@
1
1
  module Forecasting
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forecasting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Owens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-29 00:00:00.000000000 Z
11
+ date: 2023-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- description: Interact with the Forecast API from your Ruby application
55
+ description: Interact with the Harvest Forecast API from your Ruby application
56
56
  email:
57
57
  - jordan@neomindlabs.com
58
58
  executables: []
@@ -109,5 +109,5 @@ requirements: []
109
109
  rubygems_version: 3.3.20
110
110
  signing_key:
111
111
  specification_version: 4
112
- summary: Ruby wrapper for the Forecast API
112
+ summary: Ruby wrapper for the Harvest Forecast API
113
113
  test_files: []