airtable2 0.2.1 → 0.2.3

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: 0fb935ffab4d6e71ec8d1d5b2dc3d333e8e594694efa066cdfb5b9cc2bc127c6
4
- data.tar.gz: 5df0a4d75e41a62e7e37083ebe86a8a907424bdc07b85415fd3322ee97c31564
3
+ metadata.gz: 32bae2cc155c84b948c193c8ea5677288ea7123aeded90f6e6121ba196d0a4c7
4
+ data.tar.gz: 8efc8479bf004389e25aee1bdc8b88b60dfbc395078dfa4935f4a65afa93bbe4
5
5
  SHA512:
6
- metadata.gz: c685dbee77e83356da763e04a4d21cd9045f590790fa1a07a3311fffa5e57f35a46c6ccad9a48763dcf42a6b056ab71421ff8303853f8e50f12e08ea6b03ed50
7
- data.tar.gz: 2a4ca8fc25b2dd248c36f5256ce3c7d57d087ada7048aa41276b20e7deb058e79e60800bcd30b71fe421dfe149fa28038b6240f3f078163c0a0367ef2ca4a0d7
6
+ metadata.gz: 9f0993c56aa18abf1fc80089ebf8b08d377ff70476c04b4df619dd6637a4439bf034a0af2b8f90660244464ceeefc137fd836cd99493b00415ea7108cead000b
7
+ data.tar.gz: b1b30151a67ff2ce1f2eb479327ef1a959fa4ca9d671ecd33553d3a75c746f1193010e5d3e1ab457cfbd3ca9e25d385a2c85cc5d850e1a3b2766ddfd65160647
data/README.md CHANGED
@@ -10,7 +10,7 @@ This is a fork of an abandoned [previous wrapper](https://github.com/nesquena/ai
10
10
 
11
11
  Add this line to your application's Gemfile:
12
12
 
13
- gem 'airtable2', github: 'https://github.com/aseroff/airtable-ruby', branch: 'main'
13
+ gem 'airtable2'
14
14
 
15
15
  And then execute:
16
16
 
@@ -41,12 +41,15 @@ and its tables
41
41
  @tables = @base.tables
42
42
  ```
43
43
 
44
- and a table's records, so you can navigate the has_many chain the way God intended:
44
+ and a table's records, so you can navigate the belongs_to/has_many relationships the way God intended:
45
45
 
46
46
  ```ruby
47
- @client.bases.first.tables.first.records.first
47
+ @record = @client.bases.first.tables.first.records.first
48
+ @base = @record.table.base
48
49
  ```
49
50
 
51
+ Note that objects' child records are memoized to avoid unnecessary API calls. If sensitive to stale data, be sure to use the objects instantiated most recently.
52
+
50
53
  ### Manipulating Tables
51
54
 
52
55
  Create a new table with:
@@ -71,10 +74,10 @@ Once you have access to a table from above, we can query a set of records in the
71
74
 
72
75
  ### Inserting Records
73
76
 
74
- A single record or an array of records can be inserted using the `add_records` method on a table (max 10 at a time):
77
+ A single record or an array of records can be inserted using the `create_records` method on a table (max 10 at a time):
75
78
 
76
79
  ```ruby
77
- @table.add_records({ 'Name': 'name value', 'Age': 35 })
80
+ @table.create_records({ 'Name': 'name value', 'Age': 35 })
78
81
  ```
79
82
 
80
83
  ### Deleting Records
@@ -92,6 +95,10 @@ Or as a convenience, you can delete all records with the `dump` method
92
95
  @table.dump
93
96
  ```
94
97
 
98
+ ## Complete documentation
99
+
100
+ YARD-generated documentation is hosted on [GitHub Pages](https://aseroff.github.io/airtable-ruby/).
101
+
95
102
  ## Contributing
96
103
 
97
104
  1. Fork it ( https://github.com/aseroff/airtable-ruby/fork )
data/airtable.gemspec CHANGED
@@ -9,19 +9,17 @@ Gem::Specification.new do |spec|
9
9
  spec.version = Airtable::VERSION
10
10
  spec.authors = ['Andrew Seroff', 'Nathan Esquenazi', 'Alexander Sorokin']
11
11
  spec.email = ['andy@seroff.co']
12
- spec.summary = 'Easily connect to airtable data using ruby'
12
+ spec.summary = 'For when Airrecord is just too much.'
13
13
  spec.description = 'Easily connect to airtable data using ruby with access to all of the airtable features.'
14
14
  spec.homepage = 'https://github.com/aseroff/airtable-ruby'
15
15
  spec.license = 'MIT'
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0")
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(docs|test)/}) }
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.required_ruby_version = '>= 3.1'
22
- spec.add_dependency 'activesupport'
23
- spec.add_dependency 'httparty'
24
- spec.add_dependency 'json'
22
+ spec.add_dependency 'httparty', '>= 0.14.0'
25
23
 
26
24
  spec.add_development_dependency 'bundler'
27
25
  spec.add_development_dependency 'minitest'
@@ -30,7 +28,9 @@ Gem::Specification.new do |spec|
30
28
  spec.add_development_dependency 'rubocop-md'
31
29
  spec.add_development_dependency 'rubocop-minitest'
32
30
  spec.add_development_dependency 'rubocop-performance'
31
+ spec.add_development_dependency 'rubocop-rake'
33
32
  spec.add_development_dependency 'webmock'
34
- spec.add_development_dependency 'yard'
33
+
35
34
  spec.metadata['rubygems_mfa_required'] = 'true'
35
+ spec.metadata['github_repo'] = 'ssh://github.com/aseroff/airtable-ruby'
36
36
  end
data/lib/airtable/base.rb CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  # Object corresponding to an Airtable Base
4
4
  class Airtable::Base < Airtable::Resource
5
- def initialize(token, id)
6
- @token = token
5
+ def initialize(token, id, tables = nil)
6
+ super(token)
7
7
  @id = id
8
- self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
8
+ @tables = tables
9
9
  end
10
10
 
11
- # Expects {name:,description:,fields:[]}
12
- # @see https://airtable.com/developers/web/api/create-table
11
+ # @param table_data [Hash] Payload for table creation. Expects {name:,description:,fields:[]}
13
12
  # @return [Airtable::Table]
13
+ # @see https://airtable.com/developers/web/api/create-table
14
14
  def create_table(table_data)
15
15
  response = self.class.post("#{base_url}/tables",
16
16
  body: table_data.to_json).parsed_response
@@ -20,17 +20,20 @@ class Airtable::Base < Airtable::Resource
20
20
  Airtable::Table.new @token, @id, response
21
21
  end
22
22
 
23
+ # @return [Array<Airtable::Table>]
23
24
  # @see https://airtable.com/developers/web/api/get-base-schema
24
- # @return [Array]<Airtable::Table>
25
25
  def tables
26
- response = self.class.get("#{base_url}/tables")
26
+ @tables ||= begin
27
+ response = self.class.get("#{base_url}/tables")
27
28
 
28
- check_and_raise_error(response)
29
+ check_and_raise_error(response)
29
30
 
30
- response['tables'].map { Airtable::Table.new(@token, @id, _1) }
31
+ response['tables'].map { Airtable::Table.new(@token, @id, _1['id'], _1) }
32
+ end
31
33
  end
32
34
 
33
35
  # Instantiate table in base
36
+ # @param table_id [String] ID of table
34
37
  # @return [Airtable::Table]
35
38
  def table(table_id)
36
39
  Airtable::Table.new(@token, @id, table_id)
@@ -38,6 +41,6 @@ class Airtable::Base < Airtable::Resource
38
41
 
39
42
  protected
40
43
 
41
- # Instantiate table in base
44
+ # Endpoint for bases
42
45
  def base_url = "/v0/meta/bases/#{@id}"
43
46
  end
@@ -2,13 +2,8 @@
2
2
 
3
3
  # Client carrying authorization token
4
4
  class Airtable::Client < Airtable::Resource
5
- def initialize(token)
6
- @token = token
7
- self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
8
- end
9
-
5
+ # @return [Array<Airtable::Base>]
10
6
  # @see https://airtable.com/developers/web/api/list-bases
11
- # @return [Array]<Airtable::Base>
12
7
  def bases
13
8
  response = self.class.get('/v0/meta/bases').parsed_response
14
9
 
@@ -17,22 +12,22 @@ class Airtable::Client < Airtable::Resource
17
12
  response['bases'].map { Airtable::Base.new(@token, _1['id']) }
18
13
  end
19
14
 
20
- # @see https://airtable.com/developers/web/api/create-base
21
- # def create_base(base_data)
22
- # response = self.class.post('/v0/meta/bases'
23
- # body: base_data.to_json).parsed_response
24
- # check_and_raise_error(response)
25
- # Airtable::Base.new @token, response
26
- # end
15
+ # Instantiate workspace
16
+ # @param workspace_id [String] ID of workspace
17
+ # @return [Airtable::Workspace]
18
+ def workspace(workspace_id)
19
+ Airtable::Workspace.new(@token, workspace_id)
20
+ end
27
21
 
28
22
  # Instantiate base
23
+ # @param base_id [String] ID of base
29
24
  # @return [Airtable::Base]
30
25
  def base(base_id)
31
26
  Airtable::Base.new(@token, base_id)
32
27
  end
33
28
 
29
+ # @return [Hash] User's data based on token
34
30
  # @see https://airtable.com/developers/web/api/get-user-id-scopes
35
- # @return [Hash]
36
31
  def whoami
37
32
  response = self.class.get('/v0/meta/whoami').parsed_response
38
33
 
@@ -2,15 +2,44 @@
2
2
 
3
3
  # Object corresponding to an Airtable Record
4
4
  class Airtable::Record < Airtable::Resource
5
- attr_reader :fields
6
-
7
- def initialize(token, base_id, table_id, api_response)
8
- @token = token
5
+ def initialize(token, base_id, table_id, id, data = nil)
6
+ super(token)
9
7
  @base_id = base_id
10
8
  @table_id = table_id
11
- api_response.deep_symbolize_keys.each do |key, value|
12
- instance_variable_set(:"@#{key}", value)
9
+ @id = id
10
+ @data = data
11
+ end
12
+
13
+ # Return record data, retrieve if not present
14
+ # @return [Hash]
15
+ # @see https://airtable.com/developers/web/api/get-record
16
+ def data
17
+ @data ||= begin
18
+ response = self.class.get(record_url).parsed_response
19
+
20
+ check_and_raise_error(response)
21
+
22
+ response
13
23
  end
14
- self.class.headers({ 'Authorization': "Bearer #{@token}", 'Content-Type': 'application/json' })
15
24
  end
25
+
26
+ # Instantiate record's table
27
+ # @return [Airtable::Table]
28
+ def table = Airtable::Table.new(token, @base_id, @table_id)
29
+
30
+ # @return [Airtable::Record]
31
+ # @see https://airtable.com/developers/web/api/update-record
32
+ def update(record_data)
33
+ response = self.class.patch(record_url,
34
+ body: { fields: record_data }.to_json).parsed_response
35
+
36
+ check_and_raise_error(response)
37
+
38
+ Airtable::Record.new @token, @base_id, @table_id, response['id'], response
39
+ end
40
+
41
+ protected
42
+
43
+ # Endpoint for records
44
+ def record_url = "/v0/#{@base_id}/#{@table_id}/#{@id}"
16
45
  end
@@ -4,46 +4,55 @@
4
4
  class Airtable::Table < Airtable::Resource
5
5
  attr_reader :name
6
6
 
7
- def initialize(token, base_id, api_response)
8
- @token = token
7
+ def initialize(token, base_id, id, data = nil)
8
+ super(token)
9
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' })
10
+ @id = id
11
+ @data = data
14
12
  end
15
13
 
16
- # @see https://airtable.com/developers/web/api/list-records
14
+ # Return table model, retrieve if not present
15
+ # @return [Hash]
16
+ # @see https://airtable.com/developers/web/api/get-base-schema
17
+ def data = @data ||= base.tables.find { _1.id == @id }.data
18
+
19
+ # Instantiate table's base
20
+ # @return [Airtable::Base]
21
+ def base = Airtable::Base.new(token, @base_id)
22
+
17
23
  # @return [Array<Airtable::Record>]
24
+ # @see https://airtable.com/developers/web/api/list-records
18
25
  def records
19
- response = self.class.get(table_url)
26
+ @records ||= begin
27
+ response = self.class.get(table_url)
20
28
 
21
- check_and_raise_error(response)
29
+ check_and_raise_error(response)
22
30
 
23
- response['records'].map { Airtable::Record.new(@token, @base_id, @table_id, _1) }
31
+ response['records'].map { Airtable::Record.new(@token, @base_id, @id, _1['id'], _1) }
32
+ end
24
33
  end
25
34
 
26
35
  # Instantiate record in table
27
- # @return [Airtable::Table]
28
- def record(record_id)
29
- Airtable::Table.new(@token, @base_id, @id, record_id)
30
- end
36
+ # @param record_id [String] ID of record
37
+ # @return [Airtable::Record]
38
+ def record(record_id) = Airtable::Record.new(@token, @base_id, @id, record_id)
31
39
 
32
- # @see https://airtable.com/developers/web/api/update-table
33
40
  # @return [Airtable::Table]
41
+ # @see https://airtable.com/developers/web/api/update-table
34
42
  def update(table_data)
35
43
  response = self.class.patch("/v0/meta/bases/#{@base_id}/tables/#{@id}",
36
44
  body: table_data.to_json).parsed_response
37
45
 
38
46
  check_and_raise_error(response)
39
47
 
40
- Airtable::Table.new @token, @base_id, response
48
+ Airtable::Table.new @token, @base_id, response['id'], response
41
49
  end
42
50
 
43
- # @note API maximum of 10 records at a time
44
- # @see https://airtable.com/developers/web/api/create-records
51
+ # @param [Array] Record objects to create
45
52
  # @return [Array<Airtable::Record>]
46
- def add_records(records)
53
+ # @see https://airtable.com/developers/web/api/create-records
54
+ # @note API maximum of 10 records at a time
55
+ def create_records(records)
47
56
  response = self.class.post(table_url,
48
57
  body: { records: Array(records).map { |fields| { fields: } } }.to_json).parsed_response
49
58
 
@@ -52,8 +61,10 @@ class Airtable::Table < Airtable::Resource
52
61
  response['records'].map { Airtable::Record.new(@token, @base_id, @id, _1) }
53
62
  end
54
63
 
55
- # @see https://airtable.com/developers/web/api/delete-multiple-records
64
+ # @param [Array] IDs of records to delete
56
65
  # @return [Array] Deleted record ids
66
+ # @see https://airtable.com/developers/web/api/delete-multiple-records
67
+ # @note API maximum of 10 records at a time
57
68
  def delete_records(record_ids)
58
69
  params = Array(record_ids).compact.map { "records[]=#{_1}" }.join('&')
59
70
  response = self.class.delete("#{table_url}?#{params}").parsed_response
@@ -73,5 +84,6 @@ class Airtable::Table < Airtable::Resource
73
84
 
74
85
  protected
75
86
 
87
+ # Endpoint for tables
76
88
  def table_url = "/v0/#{@base_id}/#{@id}"
77
89
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version
4
4
  module Airtable
5
- VERSION = '0.2.1'
5
+ VERSION = '0.2.3'
6
6
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Object corresponding to an Airtable Workspace
4
+ class Airtable::Workspace < Airtable::Resource
5
+ def initialize(token, id)
6
+ super(token)
7
+ @id = id
8
+ end
9
+
10
+ # @param base_data [Hash] Payload for base
11
+ # @see https://airtable.com/developers/web/api/create-base
12
+ def create_base(base_data)
13
+ response = self.class.post('/v0/meta/bases',
14
+ body: base_data.merge({ workspaceId: @id }).to_json).parsed_response
15
+
16
+ check_and_raise_error(response)
17
+
18
+ Airtable::Base.new @token, response
19
+ end
20
+ end
data/lib/airtable.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'httparty'
4
- require 'delegate'
5
- require 'active_support/core_ext/hash'
6
4
  require 'json'
7
5
 
8
6
  require 'airtable/version'
@@ -10,5 +8,6 @@ require 'airtable/resource'
10
8
  require 'airtable/record'
11
9
  require 'airtable/table'
12
10
  require 'airtable/base'
11
+ require 'airtable/workspace'
13
12
  require 'airtable/client'
14
13
  require 'airtable/error'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airtable2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Seroff
@@ -10,50 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-10-26 00:00:00.000000000 Z
13
+ date: 2024-10-28 00:00:00.000000000 Z
14
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
15
  - !ruby/object:Gem::Dependency
30
16
  name: httparty
31
17
  requirement: !ruby/object:Gem::Requirement
32
18
  requirements:
33
19
  - - ">="
34
20
  - !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'
21
+ version: 0.14.0
50
22
  type: :runtime
51
23
  prerelease: false
52
24
  version_requirements: !ruby/object:Gem::Requirement
53
25
  requirements:
54
26
  - - ">="
55
27
  - !ruby/object:Gem::Version
56
- version: '0'
28
+ version: 0.14.0
57
29
  - !ruby/object:Gem::Dependency
58
30
  name: bundler
59
31
  requirement: !ruby/object:Gem::Requirement
@@ -153,7 +125,7 @@ dependencies:
153
125
  - !ruby/object:Gem::Version
154
126
  version: '0'
155
127
  - !ruby/object:Gem::Dependency
156
- name: webmock
128
+ name: rubocop-rake
157
129
  requirement: !ruby/object:Gem::Requirement
158
130
  requirements:
159
131
  - - ">="
@@ -167,7 +139,7 @@ dependencies:
167
139
  - !ruby/object:Gem::Version
168
140
  version: '0'
169
141
  - !ruby/object:Gem::Dependency
170
- name: yard
142
+ name: webmock
171
143
  requirement: !ruby/object:Gem::Requirement
172
144
  requirements:
173
145
  - - ">="
@@ -195,27 +167,6 @@ files:
195
167
  - README.md
196
168
  - Rakefile
197
169
  - airtable.gemspec
198
- - docs/Airtable.html
199
- - docs/Airtable/Base.html
200
- - docs/Airtable/Client.html
201
- - docs/Airtable/Error.html
202
- - docs/Airtable/Record.html
203
- - docs/Airtable/Resource.html
204
- - docs/Airtable/Table.html
205
- - docs/_index.html
206
- - docs/class_list.html
207
- - docs/css/common.css
208
- - docs/css/full_list.css
209
- - docs/css/style.css
210
- - docs/file.README.html
211
- - docs/file_list.html
212
- - docs/frames.html
213
- - docs/index.html
214
- - docs/js/app.js
215
- - docs/js/full_list.js
216
- - docs/js/jquery.js
217
- - docs/method_list.html
218
- - docs/top-level-namespace.html
219
170
  - lib/airtable.rb
220
171
  - lib/airtable/base.rb
221
172
  - lib/airtable/client.rb
@@ -224,14 +175,13 @@ files:
224
175
  - lib/airtable/resource.rb
225
176
  - lib/airtable/table.rb
226
177
  - lib/airtable/version.rb
227
- - test/airtable_test.rb
228
- - test/record_test.rb
229
- - test/test_helper.rb
178
+ - lib/airtable/workspace.rb
230
179
  homepage: https://github.com/aseroff/airtable-ruby
231
180
  licenses:
232
181
  - MIT
233
182
  metadata:
234
183
  rubygems_mfa_required: 'true'
184
+ github_repo: ssh://github.com/aseroff/airtable-ruby
235
185
  post_install_message:
236
186
  rdoc_options: []
237
187
  require_paths:
@@ -247,8 +197,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
197
  - !ruby/object:Gem::Version
248
198
  version: '0'
249
199
  requirements: []
250
- rubygems_version: 3.5.21
200
+ rubygems_version: 3.5.22
251
201
  signing_key:
252
202
  specification_version: 4
253
- summary: Easily connect to airtable data using ruby
203
+ summary: For when Airrecord is just too much.
254
204
  test_files: []