attio-rails 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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +42 -0
- data/.github/workflows/ci.yml +74 -0
- data/.github/workflows/docs.yml +51 -0
- data/.github/workflows/release.yml +70 -0
- data/.gitignore +60 -0
- data/.rspec +4 -0
- data/.rubocop.yml +65 -0
- data/.yardopts +14 -0
- data/CHANGELOG.md +32 -0
- data/CODE_OF_CONDUCT.md +37 -0
- data/CONTRIBUTING.md +241 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +243 -0
- data/Rakefile +29 -0
- data/SECURITY.md +63 -0
- data/attio-rails.gemspec +42 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/index.html +91 -0
- data/lib/attio/rails/concerns/syncable.rb +132 -0
- data/lib/attio/rails/configuration.rb +55 -0
- data/lib/attio/rails/railtie.rb +15 -0
- data/lib/attio/rails/version.rb +5 -0
- data/lib/attio/rails.rb +13 -0
- data/lib/generators/attio/install/install_generator.rb +65 -0
- data/lib/generators/attio/install/templates/README.md +39 -0
- data/lib/generators/attio/install/templates/attio.rb +7 -0
- data/lib/generators/attio/install/templates/attio_sync_job.rb +63 -0
- data/lib/generators/attio/install/templates/migration.rb +11 -0
- data/test_basic.rb +39 -0
- metadata +229 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Attio
|
2
|
+
module Rails
|
3
|
+
class Configuration
|
4
|
+
attr_accessor :api_key, :default_workspace_id, :logger, :sync_enabled, :background_sync
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@api_key = ENV['ATTIO_API_KEY']
|
8
|
+
@default_workspace_id = nil
|
9
|
+
@logger = defined?(::Rails) ? ::Rails.logger : Logger.new(STDOUT)
|
10
|
+
@sync_enabled = true
|
11
|
+
@background_sync = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
!api_key.nil? && !api_key.empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_writer :configuration
|
21
|
+
|
22
|
+
def configuration
|
23
|
+
@configuration ||= Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def configure
|
27
|
+
yield(configuration)
|
28
|
+
reset_client!
|
29
|
+
end
|
30
|
+
|
31
|
+
def client
|
32
|
+
raise ConfigurationError, "Attio API key not configured" unless configuration.valid?
|
33
|
+
@client ||= ::Attio.client(api_key: configuration.api_key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def reset_client!
|
37
|
+
@client = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def sync_enabled?
|
41
|
+
configuration.sync_enabled
|
42
|
+
end
|
43
|
+
|
44
|
+
def background_sync?
|
45
|
+
configuration.background_sync
|
46
|
+
end
|
47
|
+
|
48
|
+
def logger
|
49
|
+
configuration.logger
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ConfigurationError < StandardError; end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Attio
|
2
|
+
module Rails
|
3
|
+
class Railtie < ::Rails::Railtie
|
4
|
+
initializer "attio.configure_rails_initialization" do
|
5
|
+
ActiveSupport.on_load(:active_record) do
|
6
|
+
require 'attio/rails/concerns/syncable'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
generators do
|
11
|
+
require 'generators/attio/install/install_generator'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/attio/rails.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
class_option :skip_job, type: :boolean, default: false, desc: "Skip creating the sync job"
|
9
|
+
class_option :skip_migration, type: :boolean, default: false, desc: "Skip creating the migration"
|
10
|
+
|
11
|
+
def check_requirements
|
12
|
+
unless defined?(ActiveJob)
|
13
|
+
say "Warning: ActiveJob is not available. Skipping job creation.", :yellow
|
14
|
+
@skip_job = true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_initializer
|
19
|
+
template 'attio.rb', 'config/initializers/attio.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_migration
|
23
|
+
return if options[:skip_migration]
|
24
|
+
|
25
|
+
if defined?(ActiveRecord)
|
26
|
+
migration_template 'migration.rb', 'db/migrate/add_attio_record_id_to_tables.rb'
|
27
|
+
else
|
28
|
+
say "ActiveRecord not detected. Skipping migration.", :yellow
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_sync_job
|
33
|
+
return if options[:skip_job] || @skip_job
|
34
|
+
|
35
|
+
template 'attio_sync_job.rb', 'app/jobs/attio_sync_job.rb'
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_to_gemfile
|
39
|
+
gem_group :production do
|
40
|
+
gem 'attio-rails'
|
41
|
+
end unless gemfile_contains?('attio-rails')
|
42
|
+
end
|
43
|
+
|
44
|
+
def display_readme
|
45
|
+
readme 'README.md'
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def gemfile_contains?(gem_name)
|
51
|
+
File.read('Gemfile').include?(gem_name)
|
52
|
+
rescue
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def rails_version
|
57
|
+
Rails::VERSION::STRING
|
58
|
+
end
|
59
|
+
|
60
|
+
def migration_version
|
61
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Attio Rails Setup
|
2
|
+
|
3
|
+
The Attio Rails gem has been installed and configured!
|
4
|
+
|
5
|
+
## Next Steps
|
6
|
+
|
7
|
+
1. Set your Attio API key in your environment variables:
|
8
|
+
```
|
9
|
+
ATTIO_API_KEY=your_api_key_here
|
10
|
+
```
|
11
|
+
|
12
|
+
2. Add the Syncable concern to models you want to sync with Attio:
|
13
|
+
```ruby
|
14
|
+
class User < ApplicationRecord
|
15
|
+
include Attio::Rails::Concerns::Syncable
|
16
|
+
|
17
|
+
syncs_with_attio 'users', {
|
18
|
+
email: :email,
|
19
|
+
name: :full_name,
|
20
|
+
company: -> (user) { user.company.name }
|
21
|
+
}
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
3. Run migrations to add the attio_record_id column to your models:
|
26
|
+
```
|
27
|
+
rails db:migrate
|
28
|
+
```
|
29
|
+
|
30
|
+
4. Your models will now automatically sync to Attio on create, update, and destroy!
|
31
|
+
|
32
|
+
## Manual Sync
|
33
|
+
|
34
|
+
You can also manually trigger syncs:
|
35
|
+
```ruby
|
36
|
+
user.sync_to_attio
|
37
|
+
```
|
38
|
+
|
39
|
+
For more information, visit: https://github.com/your-username/attio-ruby
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class AttioSyncJob < ApplicationJob
|
2
|
+
queue_as :low
|
3
|
+
|
4
|
+
retry_on Attio::RateLimitError, wait: 1.minute, attempts: 3
|
5
|
+
retry_on Attio::ServerError, wait: :exponentially_longer, attempts: 5
|
6
|
+
discard_on ActiveJob::DeserializationError
|
7
|
+
|
8
|
+
def perform(model_name:, model_id:, action:, attio_record_id: nil)
|
9
|
+
return unless Attio::Rails.sync_enabled?
|
10
|
+
|
11
|
+
model_class = model_name.constantize
|
12
|
+
|
13
|
+
case action
|
14
|
+
when :sync
|
15
|
+
sync_record(model_class, model_id)
|
16
|
+
when :delete
|
17
|
+
delete_record(model_class, model_id, attio_record_id)
|
18
|
+
else
|
19
|
+
Attio::Rails.logger.error "Unknown Attio sync action: #{action}"
|
20
|
+
end
|
21
|
+
rescue Attio::AuthenticationError => e
|
22
|
+
Attio::Rails.logger.error "Attio authentication failed: #{e.message}"
|
23
|
+
raise # Re-raise to trigger job failure notifications
|
24
|
+
rescue Attio::ValidationError => e
|
25
|
+
Attio::Rails.logger.error "Attio validation error for #{model_name}##{model_id}: #{e.message}"
|
26
|
+
# Don't retry validation errors
|
27
|
+
rescue StandardError => e
|
28
|
+
Attio::Rails.logger.error "Attio sync failed for #{model_name}##{model_id}: #{e.message}"
|
29
|
+
Attio::Rails.logger.error e.backtrace.join("\n") if Rails.env.development?
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def sync_record(model_class, model_id)
|
36
|
+
model = model_class.find_by(id: model_id)
|
37
|
+
return unless model
|
38
|
+
|
39
|
+
# Check if model should still be synced
|
40
|
+
return unless model.should_sync_to_attio?
|
41
|
+
|
42
|
+
model.sync_to_attio_now
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_record(model_class, model_id, attio_record_id)
|
46
|
+
return unless attio_record_id.present?
|
47
|
+
|
48
|
+
# Model might already be deleted, so we work with the class
|
49
|
+
object_type = model_class.attio_object_type
|
50
|
+
return unless object_type.present?
|
51
|
+
|
52
|
+
client = Attio::Rails.client
|
53
|
+
client.records.delete(
|
54
|
+
object: object_type,
|
55
|
+
id: attio_record_id
|
56
|
+
)
|
57
|
+
|
58
|
+
Attio::Rails.logger.info "Deleted Attio record #{attio_record_id} for #{model_class.name}##{model_id}"
|
59
|
+
rescue Attio::NotFoundError
|
60
|
+
# Record already deleted in Attio, nothing to do
|
61
|
+
Attio::Rails.logger.info "Attio record #{attio_record_id} already deleted"
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddAttioRecordIdToTables < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
# Add attio_record_id to each table that needs to sync with Attio
|
4
|
+
# Example:
|
5
|
+
# add_column :users, :attio_record_id, :string
|
6
|
+
# add_index :users, :attio_record_id
|
7
|
+
#
|
8
|
+
# add_column :companies, :attio_record_id, :string
|
9
|
+
# add_index :companies, :attio_record_id
|
10
|
+
end
|
11
|
+
end
|
data/test_basic.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Test without loading external dependencies
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.expand_path('../../attio/lib', __FILE__))
|
6
|
+
|
7
|
+
puts "Testing Attio Rails gem structure..."
|
8
|
+
|
9
|
+
# Test version file
|
10
|
+
require 'attio/rails/version'
|
11
|
+
puts "✓ Version loaded: #{Attio::Rails::VERSION}"
|
12
|
+
|
13
|
+
# Test that all files exist
|
14
|
+
files_to_check = [
|
15
|
+
'lib/attio/rails.rb',
|
16
|
+
'lib/attio/rails/configuration.rb',
|
17
|
+
'lib/attio/rails/concerns/syncable.rb',
|
18
|
+
'lib/attio/rails/railtie.rb',
|
19
|
+
'lib/generators/attio/install/install_generator.rb',
|
20
|
+
'lib/generators/attio/install/templates/attio.rb',
|
21
|
+
'lib/generators/attio/install/templates/attio_sync_job.rb',
|
22
|
+
'lib/generators/attio/install/templates/migration.rb',
|
23
|
+
'lib/generators/attio/install/templates/README.md'
|
24
|
+
]
|
25
|
+
|
26
|
+
files_to_check.each do |file|
|
27
|
+
if File.exist?(file)
|
28
|
+
puts "✓ #{file} exists"
|
29
|
+
else
|
30
|
+
puts "✗ #{file} is missing!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Test spec files exist
|
35
|
+
spec_files = Dir.glob('spec/**/*_spec.rb')
|
36
|
+
puts "\nFound #{spec_files.length} spec files:"
|
37
|
+
spec_files.each { |f| puts " - #{f}" }
|
38
|
+
|
39
|
+
puts "\nBasic structure test completed!"
|
metadata
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attio-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ernest Sim
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: attio
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0.1'
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0.1'
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.1.1
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rails
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '6.1'
|
39
|
+
- - "<"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '8.0'
|
42
|
+
type: :runtime
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '6.1'
|
49
|
+
- - "<"
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '8.0'
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: yard
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - "~>"
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0.9'
|
59
|
+
type: :development
|
60
|
+
prerelease: false
|
61
|
+
version_requirements: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - "~>"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0.9'
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: redcarpet
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - "~>"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '3.5'
|
73
|
+
type: :development
|
74
|
+
prerelease: false
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '3.5'
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - "~>"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '3.12'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '3.12'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rubocop
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '1.50'
|
101
|
+
type: :development
|
102
|
+
prerelease: false
|
103
|
+
version_requirements: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '1.50'
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: simplecov
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - "~>"
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0.22'
|
115
|
+
type: :development
|
116
|
+
prerelease: false
|
117
|
+
version_requirements: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - "~>"
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0.22'
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: rake
|
124
|
+
requirement: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - "~>"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '13.0'
|
129
|
+
type: :development
|
130
|
+
prerelease: false
|
131
|
+
version_requirements: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - "~>"
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '13.0'
|
136
|
+
- !ruby/object:Gem::Dependency
|
137
|
+
name: bundler-audit
|
138
|
+
requirement: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - "~>"
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0.9'
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0.9'
|
150
|
+
- !ruby/object:Gem::Dependency
|
151
|
+
name: danger
|
152
|
+
requirement: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - "~>"
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '9.4'
|
157
|
+
type: :development
|
158
|
+
prerelease: false
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - "~>"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '9.4'
|
164
|
+
description: Rails-specific features and integrations for the Attio Ruby client, including
|
165
|
+
model concerns and generators
|
166
|
+
email:
|
167
|
+
- ernest.codes@gmail.com
|
168
|
+
executables: []
|
169
|
+
extensions: []
|
170
|
+
extra_rdoc_files: []
|
171
|
+
files:
|
172
|
+
- ".github/dependabot.yml"
|
173
|
+
- ".github/workflows/ci.yml"
|
174
|
+
- ".github/workflows/docs.yml"
|
175
|
+
- ".github/workflows/release.yml"
|
176
|
+
- ".gitignore"
|
177
|
+
- ".rspec"
|
178
|
+
- ".rubocop.yml"
|
179
|
+
- ".yardopts"
|
180
|
+
- CHANGELOG.md
|
181
|
+
- CODE_OF_CONDUCT.md
|
182
|
+
- CONTRIBUTING.md
|
183
|
+
- Gemfile
|
184
|
+
- LICENSE.txt
|
185
|
+
- README.md
|
186
|
+
- Rakefile
|
187
|
+
- SECURITY.md
|
188
|
+
- attio-rails.gemspec
|
189
|
+
- bin/console
|
190
|
+
- bin/setup
|
191
|
+
- docs/index.html
|
192
|
+
- lib/attio/rails.rb
|
193
|
+
- lib/attio/rails/concerns/syncable.rb
|
194
|
+
- lib/attio/rails/configuration.rb
|
195
|
+
- lib/attio/rails/railtie.rb
|
196
|
+
- lib/attio/rails/version.rb
|
197
|
+
- lib/generators/attio/install/install_generator.rb
|
198
|
+
- lib/generators/attio/install/templates/README.md
|
199
|
+
- lib/generators/attio/install/templates/attio.rb
|
200
|
+
- lib/generators/attio/install/templates/attio_sync_job.rb
|
201
|
+
- lib/generators/attio/install/templates/migration.rb
|
202
|
+
- test_basic.rb
|
203
|
+
homepage: https://github.com/idl3/attio-rails
|
204
|
+
licenses:
|
205
|
+
- MIT
|
206
|
+
metadata:
|
207
|
+
allowed_push_host: https://rubygems.org
|
208
|
+
homepage_uri: https://github.com/idl3/attio-rails
|
209
|
+
source_code_uri: https://github.com/idl3/attio-rails
|
210
|
+
changelog_uri: https://github.com/idl3/attio-rails/blob/main/CHANGELOG.md
|
211
|
+
documentation_uri: https://idl3.github.io/attio-rails
|
212
|
+
rdoc_options: []
|
213
|
+
require_paths:
|
214
|
+
- lib
|
215
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: 3.0.0
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
requirements:
|
222
|
+
- - ">="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: '0'
|
225
|
+
requirements: []
|
226
|
+
rubygems_version: 3.6.9
|
227
|
+
specification_version: 4
|
228
|
+
summary: Rails integration for the Attio API client
|
229
|
+
test_files: []
|