airtable2 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 +7 -0
- data/.gitignore +24 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +23 -0
- data/README.md +95 -0
- data/Rakefile +9 -0
- data/airtable.gemspec +35 -0
- data/lib/airtable/base.rb +32 -0
- data/lib/airtable/client.rb +12 -0
- data/lib/airtable/error.rb +14 -0
- data/lib/airtable/record.rb +16 -0
- data/lib/airtable/resource.rb +19 -0
- data/lib/airtable/table.rb +62 -0
- data/lib/airtable/version.rb +6 -0
- data/lib/airtable.rb +14 -0
- data/test/airtable_test.rb +82 -0
- data/test/record_test.rb +23 -0
- data/test/test_helper.rb +15 -0
- metadata +218 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8e76de7af1e8850fd762c839dcee996e5ce71e10c800548e991f80500da1c68d
|
4
|
+
data.tar.gz: 83ea6edb7e3a1473b1531f7dc3cee9273f6abdf2864e4c2bfa98051bd6667ea0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 651355e1f16d59ed0c96ba2088c65824bc97c707cc1cf2d34967a13a399abf6ff1e00bd424c38bc2ce5efc24bb47e0594c24b2e3ae606940cb3311a4c4da5b77
|
7
|
+
data.tar.gz: b5e46f6aee0d721703feaa4f615f819ac433a64d5dd625297d8d12479032dd7bf940684ab3027ef65bcdabd9d1175399ecc4ad758dabaa68155a201cdbc05435
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.vscode
|
6
|
+
.yardoc
|
7
|
+
Gemfile.lock
|
8
|
+
InstalledFiles
|
9
|
+
_yardoc
|
10
|
+
coverage
|
11
|
+
doc/
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
test/tmp
|
17
|
+
test/version_tmp
|
18
|
+
tmp
|
19
|
+
*.bundle
|
20
|
+
*.so
|
21
|
+
*.o
|
22
|
+
*.a
|
23
|
+
mkmf.log
|
24
|
+
.DS_Store
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2015 Nathan Esquenazi
|
2
|
+
Copyright (c) 2016 Airtable
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Airtable API Wrapper for Ruby
|
2
|
+
|
3
|
+
For when Airrecord is just too much.
|
4
|
+
|
5
|
+
# Note on library status
|
6
|
+
|
7
|
+
This is a fork of an abandoned [previous wrapper](https://github.com/nesquena/airtable-ruby). There's still plenty to do to get it up to speed with the current Airtable API.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'airtable2', github: 'https://github.com/aseroff/airtable-ruby', branch: 'main'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Creating a Client
|
22
|
+
|
23
|
+
First, be sure to register for an [airtable](https://airtable.com) account, setup a base, and create a token with the desired permissions for your base. Now, setup your Airtable client:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Pass in api key to client
|
27
|
+
@client = Airtable::Client.new('your.token.goes.here')
|
28
|
+
```
|
29
|
+
|
30
|
+
### Accessing Data
|
31
|
+
|
32
|
+
Now we can access our base
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
@base = @client.base('appExAmPlE')
|
36
|
+
```
|
37
|
+
|
38
|
+
and its tables
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
@tables = @base.tables
|
42
|
+
```
|
43
|
+
|
44
|
+
and create a new table
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
@table = @base.create_table({ name: 'Names', description: 'A list of names', fields: [{ name: 'name', type: 'singleLineText' }] })
|
48
|
+
```
|
49
|
+
|
50
|
+
### Manipulating Tables
|
51
|
+
|
52
|
+
You can update at a table's metadata with the `update` method:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
@table.update({ description: 'Updated description' })
|
56
|
+
```
|
57
|
+
|
58
|
+
### Querying Records
|
59
|
+
|
60
|
+
Once you have access to a table from above, we can query a set of records in the table with:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
@records = @table.records
|
64
|
+
```
|
65
|
+
|
66
|
+
### Inserting Records
|
67
|
+
|
68
|
+
A single record or an array of records can be inserted using the `add_records` method on a table (max 10 at a time):
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
@table.add_records({ 'Name': 'name value', 'Age': 35 })
|
72
|
+
```
|
73
|
+
|
74
|
+
### Deleting Records
|
75
|
+
|
76
|
+
A single record or an array of records can be destroyed by passing their ids to the `delete_records` method on a table:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
@record = @table.records[0]
|
80
|
+
@table.delete_records(@record.id)
|
81
|
+
```
|
82
|
+
|
83
|
+
Or as a convenience, you can delete all records with the `dump` method
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
@table.dump
|
87
|
+
```
|
88
|
+
|
89
|
+
## Contributing
|
90
|
+
|
91
|
+
1. Fork it ( https://github.com/aseroff/airtable-ruby/fork )
|
92
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
93
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
94
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
95
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/airtable.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'airtable/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'airtable2'
|
9
|
+
spec.version = Airtable::VERSION
|
10
|
+
spec.authors = ['Andrew Seroff', 'Nathan Esquenazi', 'Alexander Sorokin']
|
11
|
+
spec.email = ['andy@seroff.co']
|
12
|
+
spec.summary = 'Easily connect to airtable data using ruby'
|
13
|
+
spec.description = 'Easily connect to airtable data using ruby with access to all of the airtable features.'
|
14
|
+
spec.homepage = 'https://github.com/aseroff/airtable-ruby'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 3.1'
|
22
|
+
spec.add_dependency 'activesupport'
|
23
|
+
spec.add_dependency 'httparty'
|
24
|
+
spec.add_dependency 'json'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler'
|
27
|
+
spec.add_development_dependency 'minitest'
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'rubocop'
|
30
|
+
spec.add_development_dependency 'rubocop-md'
|
31
|
+
spec.add_development_dependency 'rubocop-minitest'
|
32
|
+
spec.add_development_dependency 'rubocop-performance'
|
33
|
+
spec.add_development_dependency 'webmock'
|
34
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Object corresponding to an Airtable Base
|
4
|
+
class Airtable::Base < Airtable::Resource
|
5
|
+
def initialize(token, id)
|
6
|
+
@token = token
|
7
|
+
@id = id
|
8
|
+
self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
|
9
|
+
end
|
10
|
+
|
11
|
+
# Expects {name:,description:,fields:[]}
|
12
|
+
def create_table(table_data)
|
13
|
+
response = self.class.post("#{base_url}/tables",
|
14
|
+
body: table_data.to_json).parsed_response
|
15
|
+
|
16
|
+
check_and_raise_error(response)
|
17
|
+
|
18
|
+
Airtable::Table.new @token, @id, response
|
19
|
+
end
|
20
|
+
|
21
|
+
def tables
|
22
|
+
response = self.class.get("#{base_url}/tables")
|
23
|
+
|
24
|
+
check_and_raise_error(response)
|
25
|
+
|
26
|
+
response['tables'].map { Airtable::Table.new(@token, @id, _1) }
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def base_url = "/v0/meta/bases/#{@id}"
|
32
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Error class
|
4
|
+
class Airtable::Error < StandardError
|
5
|
+
attr_reader :message, :type
|
6
|
+
|
7
|
+
# {"error"=>{"type"=>"UNKNOWN_COLUMN_NAME", "message"=>"Could not find fields foo"}}
|
8
|
+
|
9
|
+
def initialize(error_hash)
|
10
|
+
@message = error_hash['message']
|
11
|
+
@type = error_hash['type']
|
12
|
+
super(@message)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Object corresponding to an Airtable Record
|
4
|
+
class Airtable::Record < Airtable::Resource
|
5
|
+
attr_reader :fields
|
6
|
+
|
7
|
+
def initialize(token, base_id, table_id, api_response)
|
8
|
+
@token = token
|
9
|
+
@base_id = base_id
|
10
|
+
@table_id = table_id
|
11
|
+
api_response.deep_symbolize_keys.each do |key, value|
|
12
|
+
instance_variable_set(:"@#{key}", value)
|
13
|
+
end
|
14
|
+
self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Base class for authorized resources sending network requests
|
4
|
+
class Airtable::Resource
|
5
|
+
include HTTParty
|
6
|
+
base_uri 'https://api.airtable.com'
|
7
|
+
# debug_output $stdout
|
8
|
+
|
9
|
+
attr_reader :id, :token
|
10
|
+
|
11
|
+
def initialize(token)
|
12
|
+
@token = token
|
13
|
+
self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_and_raise_error(response)
|
17
|
+
response['error'] ? raise(Error, response['error']) : false
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Object corresponding to an Airtable Table
|
4
|
+
class Airtable::Table < Airtable::Resource
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(token, base_id, api_response)
|
8
|
+
@token = token
|
9
|
+
@base_id = base_id
|
10
|
+
api_response.deep_symbolize_keys.each do |key, value|
|
11
|
+
instance_variable_set(:"@#{key}", value)
|
12
|
+
end
|
13
|
+
self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
|
14
|
+
end
|
15
|
+
|
16
|
+
def records
|
17
|
+
response = self.class.get(table_url)
|
18
|
+
|
19
|
+
check_and_raise_error(response)
|
20
|
+
|
21
|
+
response['records'].map { Airtable::Record.new(@token, @base_id, @table_id, _1) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(table_data)
|
25
|
+
response = self.class.patch("/v0/meta/bases/#{@base_id}/tables/#{@id}",
|
26
|
+
body: table_data.to_json).parsed_response
|
27
|
+
|
28
|
+
check_and_raise_error(response)
|
29
|
+
|
30
|
+
Airtable::Table.new @token, @base_id, response
|
31
|
+
end
|
32
|
+
|
33
|
+
# limit 10 records
|
34
|
+
def add_records(records)
|
35
|
+
response = self.class.post(table_url,
|
36
|
+
body: { records: Array(records).map { |fields| { fields: } } }.to_json).parsed_response
|
37
|
+
|
38
|
+
check_and_raise_error(response)
|
39
|
+
|
40
|
+
response['records'].map { Airtable::Record.new(@token, @base_id, @id, _1) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_records(record_ids)
|
44
|
+
params = Array(record_ids).compact.map { "records[]=#{_1}" }.join('&')
|
45
|
+
response = self.class.delete("#{table_url}?#{params}").parsed_response
|
46
|
+
|
47
|
+
check_and_raise_error(response)
|
48
|
+
|
49
|
+
record_ids
|
50
|
+
end
|
51
|
+
|
52
|
+
def dump
|
53
|
+
records.map(&:id).each_slice(10) do |record_id_set|
|
54
|
+
delete_records(record_id_set)
|
55
|
+
sleep(0.2)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def table_url = "/v0/#{@base_id}/#{@id}"
|
62
|
+
end
|
data/lib/airtable.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'delegate'
|
5
|
+
require 'active_support/core_ext/hash'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
require 'airtable/version'
|
9
|
+
require 'airtable/resource'
|
10
|
+
require 'airtable/record'
|
11
|
+
require 'airtable/table'
|
12
|
+
require 'airtable/base'
|
13
|
+
require 'airtable/client'
|
14
|
+
require 'airtable/error'
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Airtable do
|
6
|
+
before do
|
7
|
+
@client_key = '12345'
|
8
|
+
@app_key = 'appXXV84Qu'
|
9
|
+
@sheet_name = 'Test'
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'with Airtable' do
|
13
|
+
it 'should allow client to be created' do
|
14
|
+
@client = Airtable::Client.new(@client_key)
|
15
|
+
|
16
|
+
assert_kind_of Airtable::Client, @client
|
17
|
+
@table = @client.table(@app_key, @sheet_name)
|
18
|
+
|
19
|
+
assert_kind_of Airtable::Table, @table
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should fetch record set' do
|
23
|
+
stub_airtable_response!("https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}",
|
24
|
+
{ 'records' => [], 'offset' => 'abcde' })
|
25
|
+
@table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
26
|
+
@records = @table.records
|
27
|
+
|
28
|
+
assert_equal 'abcde', @records.offset
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should select records based on a formula' do
|
32
|
+
query_str = "OR(RECORD_ID() = 'recXYZ1', RECORD_ID() = 'recXYZ2', RECORD_ID() = 'recXYZ3', RECORD_ID() = 'recXYZ4')"
|
33
|
+
escaped_query = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER.call(filterByFormula: query_str)
|
34
|
+
request_url = "https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}?#{escaped_query}"
|
35
|
+
stub_airtable_response!(request_url, { 'records' => [] })
|
36
|
+
@table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
37
|
+
@select_records = @table.select(formula: query_str)
|
38
|
+
|
39
|
+
assert_empty @select_records.records
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should raise an ArgumentError if a formula is not a string' do
|
43
|
+
stub_airtable_response!("https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}",
|
44
|
+
{ 'records' => [], 'offset' => 'abcde' })
|
45
|
+
@table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
46
|
+
_ { proc { @table.select(formula: { foo: 'bar' }) } }.must_raise ArgumentError
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should allow creating records' do
|
50
|
+
stub_airtable_response!("https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}",
|
51
|
+
{ 'fields' => { 'name' => 'Sarah Jaine', 'email' => 'sarah@jaine.com', 'foo' => 'bar' }, 'id' => '12345' }, :post)
|
52
|
+
table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
53
|
+
record = Airtable::Record.new(name: 'Sarah Jaine', email: 'sarah@jaine.com')
|
54
|
+
table.create(record)
|
55
|
+
|
56
|
+
assert_equal '12345', record['id']
|
57
|
+
assert_equal 'bar', record['foo']
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should allow updating records' do
|
61
|
+
record_id = '12345'
|
62
|
+
stub_airtable_response!("https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}/#{record_id}",
|
63
|
+
{ 'fields' => { 'name' => 'Sarah Jaine', 'email' => 'sarah@jaine.com', 'foo' => 'bar' }, 'id' => record_id }, :put)
|
64
|
+
table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
65
|
+
record = Airtable::Record.new(name: 'Sarah Jaine', email: 'sarah@jaine.com', id: record_id)
|
66
|
+
table.update(record)
|
67
|
+
|
68
|
+
assert_equal '12345', record['id']
|
69
|
+
assert_equal 'bar', record['foo']
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should raise an error when the API returns an error' do
|
73
|
+
stub_airtable_response!("https://api.airtable.com/v0/#{@app_key}/#{@sheet_name}",
|
74
|
+
{ 'error' => { 'type' => 'UNKNOWN_COLUMN_NAME', 'message' => 'Could not find fields foo' } }, :post, 422)
|
75
|
+
table = Airtable::Client.new(@client_key).table(@app_key, @sheet_name)
|
76
|
+
record = Airtable::Record.new(foo: 'bar')
|
77
|
+
assert_raises Airtable::Error do
|
78
|
+
table.create(record)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/test/record_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Airtable do
|
6
|
+
describe Airtable::Record do
|
7
|
+
it 'should not return id in fields_for_update' do
|
8
|
+
record = Airtable::Record.new(name: 'Sarah Jaine', email: 'sarah@jaine.com', id: 12_345)
|
9
|
+
_(record.fields_for_update).wont_include(:id)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns new columns in fields_for_update' do
|
13
|
+
record = Airtable::Record.new(name: 'Sarah Jaine', email: 'sarah@jaine.com', id: 12_345)
|
14
|
+
record[:website] = 'http://sarahjaine.com'
|
15
|
+
_(record.fields_for_update).must_include(:website)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns fields_for_update in original capitalization' do
|
19
|
+
record = Airtable::Record.new('Name' => 'Sarah Jaine')
|
20
|
+
_(record.fields_for_update).must_include('Name')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'airtable'
|
4
|
+
require 'webmock/minitest'
|
5
|
+
require 'minitest/pride'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
|
8
|
+
def stub_airtable_response!(url, response, method = :get, status = 200)
|
9
|
+
stub_request(method, url)
|
10
|
+
.to_return(
|
11
|
+
body: response.to_json,
|
12
|
+
status: status,
|
13
|
+
headers: { 'Content-Type' => 'application/json' }
|
14
|
+
)
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: airtable2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Seroff
|
8
|
+
- Nathan Esquenazi
|
9
|
+
- Alexander Sorokin
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2024-10-26 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: httparty
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: json
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: bundler
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: minitest
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: rake
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: rubocop
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rubocop-md
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: rubocop-minitest
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: rubocop-performance
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
type: :development
|
149
|
+
prerelease: false
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: webmock
|
157
|
+
requirement: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
type: :development
|
163
|
+
prerelease: false
|
164
|
+
version_requirements: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
description: Easily connect to airtable data using ruby with access to all of the
|
170
|
+
airtable features.
|
171
|
+
email:
|
172
|
+
- andy@seroff.co
|
173
|
+
executables: []
|
174
|
+
extensions: []
|
175
|
+
extra_rdoc_files: []
|
176
|
+
files:
|
177
|
+
- ".gitignore"
|
178
|
+
- Gemfile
|
179
|
+
- LICENSE.txt
|
180
|
+
- README.md
|
181
|
+
- Rakefile
|
182
|
+
- airtable.gemspec
|
183
|
+
- lib/airtable.rb
|
184
|
+
- lib/airtable/base.rb
|
185
|
+
- lib/airtable/client.rb
|
186
|
+
- lib/airtable/error.rb
|
187
|
+
- lib/airtable/record.rb
|
188
|
+
- lib/airtable/resource.rb
|
189
|
+
- lib/airtable/table.rb
|
190
|
+
- lib/airtable/version.rb
|
191
|
+
- test/airtable_test.rb
|
192
|
+
- test/record_test.rb
|
193
|
+
- test/test_helper.rb
|
194
|
+
homepage: https://github.com/aseroff/airtable-ruby
|
195
|
+
licenses:
|
196
|
+
- MIT
|
197
|
+
metadata:
|
198
|
+
rubygems_mfa_required: 'true'
|
199
|
+
post_install_message:
|
200
|
+
rdoc_options: []
|
201
|
+
require_paths:
|
202
|
+
- lib
|
203
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - ">="
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '3.1'
|
208
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
requirements: []
|
214
|
+
rubygems_version: 3.5.21
|
215
|
+
signing_key:
|
216
|
+
specification_version: 4
|
217
|
+
summary: Easily connect to airtable data using ruby
|
218
|
+
test_files: []
|