operto 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cf8a26aabacf6a653ef155a836d95ef727b29794a0f1fbdf1365d2306ba0a4b
4
- data.tar.gz: 300fc9d056683aa3d1cedc322b887b263b454c4449a84592875484624dafd320
3
+ metadata.gz: 31bc34a291dadd87aded5937654fc9824be5cc365e94010724ef763b75169b49
4
+ data.tar.gz: 46b42729bb8e8590b02452b56c83fe4387638e5db2bee5b290f6f98040196d63
5
5
  SHA512:
6
- metadata.gz: 12713010ba3c3b7b909e1c54e959bf00411647352f959862446f54c40ad443461af683c141057f0cf59e192191cb8866ee04c82bba929ddad6b7857fa3c2ae4f
7
- data.tar.gz: e609b53f901d429bc8957decbf04029e26b815e7ae266f1929d3d3000810026a10025111c9b2ab3854987d12aded73cdc23d1175a2253d15a10e4a9c12a7beaa
6
+ metadata.gz: 0cc0aa3b12cb92f0d521dfa5f46e6a834a69ddb047a881f9eb125a12a829bc5ff4ca2b9210a8c18b48f9df761abc81ad7374133fd2bac236dac55d6199cae374
7
+ data.tar.gz: 8579d576182fc7598faf1bc8a4fa5e7e166a995def47059412a00a74ab23f5854225ea702468611f4116a76a29db45ab6469a73182437b1e02b5222c449a27fb
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 - 2026-09-27
4
+
5
+ - `Tasks::Index` returns the whole task: rule, booking, name, description, start and due times, and the active and completion flags.
6
+ - Add `Tasks::Show` for one task. A missing task fails with `Operto::NotFoundError`.
7
+ - `Tasks::Update` sends only the attributes it gets, so a description-only update keeps the name, schedule and rule.
8
+
9
+ ## 0.2.0 - 2026-08-17
10
+
11
+ - Add RBS type signatures for the public API.
12
+ - Add RubyGems project, changelog, and license metadata.
13
+ - Package the README, changelog, and license with the gem.
14
+ - Bound runtime dependencies to the supported major versions.
15
+
16
+ ## 0.1.0 - 2026-07-23
17
+
18
+ - Initial release of the Operto Teams API client, including the default in-memory token store.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Guestit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Operto
2
+
3
+ A Ruby client for the [Operto Teams](https://teams.operto.com) API. Every call
4
+ is an operation returning a [`Dry::Monads::Result`](https://dry-rb.org/gems/dry-monads/);
5
+ credentials and token storage are injected by the host, so the gem carries no
6
+ framework dependency.
7
+
8
+ ## Installation
9
+
10
+ ```ruby
11
+ # Gemfile
12
+ gem 'operto', '~> 0.3.0'
13
+ ```
14
+
15
+ ```sh
16
+ bundle install
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ Configure once at boot with your API credentials and a token store. In Rails,
22
+ put this in `config/initializers/operto.rb`:
23
+
24
+ ```ruby
25
+ Rails.application.config.to_prepare do
26
+ Operto.configure do |config|
27
+ config.client_id = Rails.application.credentials.dig(:operto, :client_id)
28
+ config.secret = Rails.application.credentials.dig(:operto, :secret)
29
+ config.token_store = MyTokenStore.new
30
+ end
31
+ end
32
+ ```
33
+
34
+ ### Token store
35
+
36
+ The gem defaults to an in-memory `Operto::MemoryTokenStore` (fine for a single
37
+ long-running process — the token re-issues after a restart). For shared or
38
+ persistent storage, provide your own store: the gem performs the OAuth
39
+ login/refresh and delegates persistence to it via four methods:
40
+
41
+ | Method | Returns / does |
42
+ | --- | --- |
43
+ | `active` | the current non-expired token, or `nil` |
44
+ | `refreshable` | a token whose refresh token is still valid, or `nil` |
45
+ | `save(access_token:, expires_at:, refresh_token: nil, refresh_expires_at: nil)` | persist and return the token |
46
+ | `clear` | drop the cached token (called after a `401`) |
47
+
48
+ A token responds to `access_token`, `refresh_token`, `refresh_expires_at`, and
49
+ `expired?`.
50
+
51
+ ## Usage
52
+
53
+ ```ruby
54
+ Operto::Tasks::Create.new.call(
55
+ attributes: {
56
+ house_id: '110784',
57
+ rule_id: '27986',
58
+ name: 'Deep clean',
59
+ start_date: Time.zone.parse('2026-01-01 09:00'),
60
+ end_date: Time.zone.parse('2026-01-02 09:00')
61
+ }
62
+ )
63
+ # => Success({ task_id: 44683131 })
64
+ ```
65
+
66
+ `#call` returns a `Result`; `#call!` unwraps it and raises the underlying
67
+ failure. Operations are grouped by resource:
68
+
69
+ - `Operto::Tasks::{Create,Update,Index,Show}`
70
+ - `Operto::StaffTasks::{Create,Destroy}` · `Operto::StaffTaskTimes::Index`
71
+ - `Operto::Issues::{Index,Close}` · `Operto::Homes::Index` · `Operto::Staff::Index`
72
+
73
+ ## Development
74
+
75
+ ```sh
76
+ bundle install
77
+ bundle exec rake # spec + rubocop
78
+ ```
79
+
80
+ HTTP interactions are recorded with [VCR](https://github.com/vcr/vcr); specs run
81
+ offline against `spec/fixtures/cassettes`.
82
+
83
+ ## License
84
+
85
+ Released under the [MIT License](LICENSE).
data/lib/operto/error.rb CHANGED
@@ -3,4 +3,7 @@ module Operto
3
3
 
4
4
  # Raised by operations for malformed arguments before any network call.
5
5
  class ArgumentError < Error; end
6
+
7
+ # Raised when Operto answers a single-record read with nothing.
8
+ class NotFoundError < Error; end
6
9
  end
@@ -46,7 +46,7 @@ module Operto
46
46
  return if value.blank?
47
47
 
48
48
  Date.strptime(value.to_s, '%Y%m%d')
49
- rescue ArgumentError
49
+ rescue Date::Error
50
50
  value
51
51
  end
52
52
  end
@@ -19,13 +19,5 @@ module Operto
19
19
  key, reason = attrs.first
20
20
  raise Operto::ArgumentError, "#{key}: #{reason}"
21
21
  end
22
-
23
- def required_attribute!(key)
24
- raise Operto::ArgumentError, "#{key}: required"
25
- end
26
-
27
- def invalid_attribute!(key, type:)
28
- raise Operto::ArgumentError, "#{key}: expected #{type}"
29
- end
30
22
  end
31
23
  end
@@ -51,7 +51,7 @@ module Operto
51
51
  return if value.blank?
52
52
 
53
53
  Date.parse(value.to_s)
54
- rescue ArgumentError
54
+ rescue Date::Error
55
55
  value
56
56
  end
57
57
  end
@@ -8,8 +8,8 @@ module Operto
8
8
  def call(attributes:)
9
9
  validate_arguments!(attributes)
10
10
 
11
- request_attributes = prepare_attributes(attributes)
12
- response = Operto::Client.connection.post('tasks', request_attributes)
11
+ # A create always sends a description, '-' when there is none.
12
+ response = Operto::Client.connection.post('tasks', request_attributes(attributes.reverse_merge(description: nil)))
13
13
 
14
14
  handle_task_response(response)
15
15
  rescue StandardError => e
@@ -22,7 +22,7 @@ module Operto
22
22
  argument! attributes: :invalid unless attributes.is_a?(Hash) && attributes.present?
23
23
 
24
24
  required_keys.each do |key|
25
- required_attribute!(key) if attributes[key].blank?
25
+ argument!(key => :required) if attributes[key].blank?
26
26
  end
27
27
  end
28
28
 
@@ -3,6 +3,7 @@ module Operto
3
3
  class Index
4
4
  include Operto::Operation
5
5
  include FilteredPagination
6
+ include Shared
6
7
 
7
8
  FILTER_MAPPINGS = {
8
9
  property_id: 'PropertyID',
@@ -37,34 +38,13 @@ module Operto
37
38
  private
38
39
 
39
40
  def format_results(body)
40
- results = body[:data].map do |task|
41
- {
42
- task_id: task[:TaskID],
43
- property_id: task[:PropertyID],
44
- approved_at: task[:ApprovedDate]&.to_datetime,
45
- completed_at: task[:CompleteConfirmedDate]&.to_datetime,
46
- staff: extract_staff(task[:Staff])
47
- }
48
- end
41
+ results = body[:data].map { |task| normalize_task(task) }
49
42
 
50
43
  {
51
44
  results:,
52
45
  count: body[:total_items] || results.size
53
46
  }
54
47
  end
55
-
56
- def extract_staff(staff_array)
57
- return [] if staff_array.blank?
58
-
59
- staff_array.map do |staff|
60
- {
61
- staff_id: staff[:StaffID],
62
- name: staff[:Name],
63
- email: staff[:Email]&.downcase,
64
- active: staff[:Active]
65
- }
66
- end
67
- end
68
48
  end
69
49
  end
70
50
  end
@@ -1,31 +1,30 @@
1
1
  module Operto
2
2
  module Tasks
3
3
  module Shared
4
- private
4
+ COMPLETED_VALUES = [true, '1', 1].freeze
5
5
 
6
- def prepare_attributes(attrs)
7
- base_attrs = {
8
- PropertyID: attrs[:house_id],
9
- TaskRuleID: attrs[:rule_id],
10
- TaskName: attrs[:name],
11
- TaskDescription: attrs[:description].presence || '-'
12
- }.compact_blank
6
+ private
13
7
 
14
- base_attrs.merge(datetime_attributes(attrs))
8
+ # Only the given keys travel, so an update never resets what the caller left out.
9
+ def request_attributes(attrs)
10
+ request = { PropertyID: attrs[:house_id], TaskRuleID: attrs[:rule_id], TaskName: attrs[:name] }.compact_blank
11
+ request[:TaskDescription] = attrs[:description].presence || '-' if attrs.key?(:description)
12
+ request.merge!(start_attributes(attrs[:start_date])) if attrs[:start_date]
13
+ request.merge!(complete_by_attributes(attrs[:end_date])) if attrs[:end_date]
14
+ request
15
15
  end
16
16
 
17
- def datetime_attributes(attrs)
18
- h = {}
17
+ def start_attributes(value)
18
+ start_date = parse_datetime(value)
19
+ date = as_date(start_date)
19
20
 
20
- start_date = parse_datetime(attrs[:start_date])
21
- h[:TaskDate] = h[:TaskStartDate] = as_date(start_date)
22
- h[:TaskTime] = h[:TaskStartTime] = start_date.hour
21
+ { TaskStartDate: date, TaskDate: date, TaskStartTime: start_date.hour, TaskTime: start_date.hour }
22
+ end
23
23
 
24
- complete_by = parse_datetime(attrs[:end_date])
25
- h[:TaskCompleteByDate] = as_date(complete_by)
26
- h[:TaskCompleteByTime] = complete_by.hour
24
+ def complete_by_attributes(value)
25
+ complete_by = parse_datetime(value)
27
26
 
28
- h
27
+ { TaskCompleteByDate: as_date(complete_by), TaskCompleteByTime: complete_by.hour }
29
28
  end
30
29
 
31
30
  def parse_datetime(value)
@@ -39,6 +38,50 @@ module Operto
39
38
  def handle_task_response(response)
40
39
  Operto::Client.handle_response(response) { |body| { task_id: body[:TaskID] } }
41
40
  end
41
+
42
+ # The list and the single-task read send "10:00" and "0"/"1"; a write echoes 10 and false.
43
+ def normalize_task(task)
44
+ {
45
+ task_id: task[:TaskID],
46
+ property_id: task[:PropertyID],
47
+ property_booking_id: task[:PropertyBookingID],
48
+ rule_id: task[:TaskRuleID],
49
+ name: task[:TaskName]&.strip,
50
+ description: task[:TaskDescription],
51
+ **task_schedule(task),
52
+ **task_progress(task)
53
+ }
54
+ end
55
+
56
+ def task_schedule(task)
57
+ {
58
+ starts_at: task_time(task[:TaskStartDate] || task[:TaskDate], task[:TaskStartTime] || task[:TaskTime]),
59
+ due_at: task_time(task[:TaskCompleteByDate], task[:TaskCompleteByTime])
60
+ }
61
+ end
62
+
63
+ def task_progress(task)
64
+ {
65
+ active: task[:TaskActive] != false,
66
+ completed: COMPLETED_VALUES.include?(task[:Completed]),
67
+ approved_at: task[:ApprovedDate]&.to_datetime,
68
+ completed_at: task[:CompleteConfirmedDate]&.to_datetime,
69
+ staff: extract_staff(task[:Staff])
70
+ }
71
+ end
72
+
73
+ def task_time(date, time)
74
+ return if date.blank?
75
+
76
+ hour, minute = time.to_s.split(':')
77
+ Time.zone.parse(date.to_s).change(hour: hour.to_i, min: minute.to_i)
78
+ end
79
+
80
+ def extract_staff(staff)
81
+ Array(staff).map do |member|
82
+ { staff_id: member[:StaffID], name: member[:Name], email: member[:Email]&.downcase, active: member[:Active] }
83
+ end
84
+ end
42
85
  end
43
86
  end
44
87
  end
@@ -0,0 +1,25 @@
1
+ module Operto
2
+ module Tasks
3
+ class Show
4
+ include Operto::Operation
5
+ include Shared
6
+
7
+ # @rbs (task_id: ::String | ::Integer) -> Dry::Monads::Result[::Hash[::Symbol, untyped]]
8
+ def call(task_id:)
9
+ argument! task_id: :required if task_id.blank?
10
+
11
+ response = Operto::Client.connection.get("tasks/#{task_id}")
12
+
13
+ Operto::Client.handle_response(response) do |body|
14
+ # A missing task comes back as an empty list, not a 404.
15
+ task = body[:data]&.first
16
+ raise Operto::NotFoundError, "Task #{task_id} not found" unless task
17
+
18
+ normalize_task(task)
19
+ end
20
+ rescue StandardError => e
21
+ Failure(e)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -4,12 +4,11 @@ module Operto
4
4
  include Operto::Operation
5
5
  include Shared
6
6
 
7
- # @rbs (task_id: ::String, attributes: ::Hash[::Symbol, untyped]) -> Dry::Monads::Result[::Hash[::Symbol, untyped]]
7
+ # @rbs (task_id: ::String | ::Integer, attributes: ::Hash[::Symbol, untyped]) -> Dry::Monads::Result[::Hash[::Symbol, untyped]]
8
8
  def call(task_id:, attributes:)
9
9
  validate_arguments!(task_id, attributes)
10
10
 
11
- request_attributes = prepare_attributes(attributes).compact_blank
12
- response = Operto::Client.connection.put("tasks/#{task_id}", request_attributes)
11
+ response = Operto::Client.connection.put("tasks/#{task_id}", request_attributes(attributes))
13
12
 
14
13
  handle_task_response(response)
15
14
  rescue StandardError => e
@@ -1,3 +1,3 @@
1
1
  module Operto
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
data/lib/operto.rb CHANGED
@@ -18,6 +18,7 @@ require_relative 'operto/tasks/shared'
18
18
  require_relative 'operto/tasks/create'
19
19
  require_relative 'operto/tasks/update'
20
20
  require_relative 'operto/tasks/index'
21
+ require_relative 'operto/tasks/show'
21
22
  require_relative 'operto/staff_tasks/create'
22
23
  require_relative 'operto/staff_tasks/destroy'
23
24
  require_relative 'operto/staff_task_times/index'
data/sig/operto.rbs ADDED
@@ -0,0 +1,121 @@
1
+ # Public API of the gem, mirroring the inline `# @rbs` annotations in lib/.
2
+ # Shipped with the gem so host apps pick it up through `rbs collection`.
3
+ module Operto
4
+ VERSION: ::String
5
+
6
+ def self.configure: () { (Config) -> void } -> void
7
+ def self.config: () -> Config
8
+
9
+ class Error < ::StandardError
10
+ end
11
+
12
+ # Raised by operations for malformed arguments before any network call.
13
+ class ArgumentError < Error
14
+ end
15
+
16
+ # Raised when Operto answers a single-record read with nothing.
17
+ class NotFoundError < Error
18
+ end
19
+
20
+ class Config
21
+ attr_accessor client_id: ::String?
22
+ attr_accessor secret: ::String?
23
+ attr_accessor base_url: ::String
24
+
25
+ # Duck-typed: the host may inject its own store (see MemoryTokenStore).
26
+ attr_accessor token_store: untyped
27
+ end
28
+
29
+ class MemoryTokenStore
30
+ REFRESH_BUFFER: ::Integer
31
+
32
+ def active: () -> untyped
33
+ def refreshable: () -> untyped
34
+ def save: (access_token: ::String, expires_at: ::Time, ?refresh_token: ::String?, ?refresh_expires_at: ::Time?) -> untyped
35
+ def clear: () -> nil
36
+ end
37
+
38
+ module IssueTypes
39
+ ISSUE_TYPES: ::Hash[::Integer, ::String]
40
+ end
41
+
42
+ # #call! returns the same Result as #call, raising the failure instead of
43
+ # wrapping it — hence the `alias call! call` on every operation below.
44
+ module Operation
45
+ def call!: (*untyped, **untyped) -> untyped
46
+ end
47
+
48
+ module AccessTokens
49
+ class Upsert
50
+ def call: () -> ::Dry::Monads::Result[untyped]
51
+ alias call! call
52
+ end
53
+ end
54
+
55
+ module Tasks
56
+ class Create
57
+ def call: (attributes: ::Hash[::Symbol, untyped]) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
58
+ alias call! call
59
+ end
60
+
61
+ class Update
62
+ def call: (task_id: ::String | ::Integer, attributes: ::Hash[::Symbol, untyped]) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
63
+ alias call! call
64
+ end
65
+
66
+ class Show
67
+ def call: (task_id: ::String | ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
68
+ alias call! call
69
+ end
70
+
71
+ class Index
72
+ def call: (?attributes: ::Hash[::Symbol, untyped], ?skip: ::Integer, ?take: ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
73
+ alias call! call
74
+ end
75
+ end
76
+
77
+ module StaffTasks
78
+ class Create
79
+ def call: (task_id: ::String, staff_id: ::String, property_id: ::String) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
80
+ alias call! call
81
+ end
82
+
83
+ class Destroy
84
+ def call: (staff_task_id: ::String) -> ::Dry::Monads::Result[bool]
85
+ alias call! call
86
+ end
87
+ end
88
+
89
+ module StaffTaskTimes
90
+ class Index
91
+ def call: (?attributes: ::Hash[::Symbol, untyped], ?skip: ::Integer, ?take: ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
92
+ alias call! call
93
+ end
94
+ end
95
+
96
+ module Issues
97
+ class Index
98
+ def call: (start_date: ::Date, ?skip: ::Integer, ?take: ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
99
+ alias call! call
100
+ end
101
+
102
+ class Close
103
+ def call: (issue_id: ::Integer | ::String) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
104
+ alias call! call
105
+ end
106
+ end
107
+
108
+ module Homes
109
+ class Index
110
+ def call: (?skip: ::Integer, ?take: ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
111
+ alias call! call
112
+ end
113
+ end
114
+
115
+ module Staff
116
+ class Index
117
+ def call: (?skip: ::Integer, ?take: ::Integer) -> ::Dry::Monads::Result[::Hash[::Symbol, untyped]]
118
+ alias call! call
119
+ end
120
+ end
121
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: operto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guestit
@@ -13,78 +13,81 @@ dependencies:
13
13
  name: activesupport
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
16
+ - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0'
18
+ version: '8.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - ">="
23
+ - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0'
25
+ version: '8.1'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: dry-monads
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
30
+ - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: '1.10'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
39
+ version: '1.10'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: faraday
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - ">="
44
+ - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0'
46
+ version: '2.14'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '2.14'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: faraday-retry
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0'
60
+ version: '2.4'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ">="
65
+ - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0'
67
+ version: '2.4'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: oj
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">="
72
+ - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: '3.17'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ">="
79
+ - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0'
81
+ version: '3.17'
82
82
  description: HTTP client and operations for the Operto Teams API, decoupled from the
83
83
  host application.
84
84
  executables: []
85
85
  extensions: []
86
86
  extra_rdoc_files: []
87
87
  files:
88
+ - CHANGELOG.md
89
+ - LICENSE
90
+ - README.md
88
91
  - lib/operto.rb
89
92
  - lib/operto/access_tokens/upsert.rb
90
93
  - lib/operto/client.rb
@@ -104,10 +107,17 @@ files:
104
107
  - lib/operto/tasks/create.rb
105
108
  - lib/operto/tasks/index.rb
106
109
  - lib/operto/tasks/shared.rb
110
+ - lib/operto/tasks/show.rb
107
111
  - lib/operto/tasks/update.rb
108
112
  - lib/operto/version.rb
109
- licenses: []
113
+ - sig/operto.rbs
114
+ homepage: https://github.com/guestitab/operto-client
115
+ licenses:
116
+ - MIT
110
117
  metadata:
118
+ allowed_push_host: https://rubygems.org
119
+ source_code_uri: https://github.com/guestitab/operto-client
120
+ changelog_uri: https://github.com/guestitab/operto-client/blob/main/CHANGELOG.md
111
121
  rubygems_mfa_required: 'true'
112
122
  rdoc_options: []
113
123
  require_paths:
@@ -123,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
133
  - !ruby/object:Gem::Version
124
134
  version: '0'
125
135
  requirements: []
126
- rubygems_version: 4.0.15
136
+ rubygems_version: 4.0.20
127
137
  specification_version: 4
128
138
  summary: Client for the Operto Teams API
129
139
  test_files: []