near 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.
@@ -0,0 +1,158 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ ##
4
+ # @see https://github.com/near/near-cli-rs/blob/main/docs/GUIDE.en.md#contract---Manage-smart-contracts-deploy-code-call-functions
5
+ module NEAR::CLI::Contract
6
+ ##
7
+ # Calls a view method on a contract (read-only).
8
+ #
9
+ # @param [String] contract_id
10
+ # @param [String] method_name
11
+ # @param [Hash] args JSON arguments for the method
12
+ # @param [Block, Integer, String, Symbol] block
13
+ # @return [String] The method call result
14
+ def view_call(contract_id, method_name, args = {}, block: :now)
15
+ stdout, _ = execute(
16
+ 'contract',
17
+ 'call-function',
18
+ 'as-read-only', contract_id, method_name,
19
+ 'json-args', args.to_json,
20
+ 'network-config', @network,
21
+ *block_args(block)
22
+ )
23
+ stdout
24
+ end
25
+
26
+ ##
27
+ # Calls a state-changing method on a contract.
28
+ #
29
+ # @param [String] contract_id
30
+ # @param [String] method_name
31
+ # @param [Hash] args JSON arguments for the method
32
+ # @param [String] signer_id Account that signs the transaction
33
+ # @param [String] deposit Amount of NEAR to attach
34
+ # @param [String] gas Amount of gas to attach
35
+ # @return [String] Transaction result
36
+ def call_function(contract_id, method_name, args = {}, signer_id:, deposit: '0 NEAR', gas: '30 TGas')
37
+ stdout, stderr = execute(
38
+ 'contract',
39
+ 'call-function',
40
+ 'as-transaction', contract_id, method_name,
41
+ 'json-args', args.to_json,
42
+ 'prepaid-gas', gas,
43
+ 'attached-deposit', deposit,
44
+ 'sign-as', signer_id,
45
+ 'network-config', @network,
46
+ 'sign-with-keychain',
47
+ 'send'
48
+ )
49
+ stderr
50
+ end
51
+ alias_method :call_method, :call_function
52
+
53
+ ##
54
+ # Deploys a new contract.
55
+ #
56
+ # @param [String] contract_id Account to deploy the contract to
57
+ # @param [String] wasm_path Path to the .wasm file
58
+ # @param [String] signer_id Account that signs the transaction
59
+ # @param [String, nil] init_method Method to call after deployment
60
+ # @param [Hash] init_args Arguments for the init method
61
+ # @param [String] init_deposit Deposit for the init method
62
+ # @param [String] init_gas Gas for the init method
63
+ # @return [String] Transaction result
64
+ def deploy_contract(contract_id, wasm_path, signer_id:, init_method: nil, init_args: {},
65
+ init_deposit: '0 NEAR', init_gas: '30 TGas')
66
+ args = [
67
+ 'contract',
68
+ 'deploy',
69
+ contract_id,
70
+ 'use-file', wasm_path
71
+ ]
72
+
73
+ if init_method
74
+ args += [
75
+ 'with-init-call', init_method,
76
+ 'json-args', init_args.to_json,
77
+ 'prepaid-gas', init_gas,
78
+ 'attached-deposit', init_deposit
79
+ ]
80
+ end
81
+
82
+ args += [
83
+ 'sign-as', signer_id,
84
+ 'network-config', @network,
85
+ 'sign-with-keychain',
86
+ 'send'
87
+ ]
88
+
89
+ stdout, stderr = execute(*args)
90
+ stderr
91
+ end
92
+
93
+ ##
94
+ # Downloads a contract's WASM code.
95
+ #
96
+ # @param [String] contract_id
97
+ # @param [String] output_path Path to write the .wasm file to
98
+ # @param [Block, Integer, String, Symbol] block
99
+ # @return [String] Path to downloaded file
100
+ def download_wasm(contract_id, output_path, block: :now)
101
+ _, _ = execute(
102
+ 'contract',
103
+ 'download-wasm', contract_id,
104
+ 'save-to-file', output_path,
105
+ 'network-config', @network,
106
+ *block_args(block)
107
+ )
108
+ output_path
109
+ end
110
+
111
+ ##
112
+ # Views contract storage state with JSON formatting.
113
+ #
114
+ # @param [String] contract_id
115
+ # @param [String, nil] prefix Filter keys by prefix
116
+ # @param [Block, Integer, String, Symbol] block
117
+ # @return [String] Contract storage state
118
+ def view_storage(contract_id, prefix: nil, block: :now)
119
+ args = [
120
+ 'contract',
121
+ 'view-storage', contract_id
122
+ ]
123
+
124
+ args += if prefix
125
+ ['keys-start-with-string', prefix]
126
+ else
127
+ ['all']
128
+ end
129
+
130
+ args += [
131
+ 'as-json',
132
+ 'network-config', @network,
133
+ *block_args(block)
134
+ ]
135
+
136
+ stdout, _ = execute(*args)
137
+ stdout
138
+ end
139
+
140
+ ##
141
+ # Views contract storage state with base64 key filtering.
142
+ #
143
+ # @param [String] contract_id
144
+ # @param [String] base64_prefix Filter keys by base64 prefix
145
+ # @param [Block, Integer, String, Symbol] block
146
+ # @return [String] Contract storage state
147
+ def view_storage_base64(contract_id, base64_prefix, block: :now)
148
+ stdout, _ = execute(
149
+ 'contract',
150
+ 'view-storage', contract_id,
151
+ 'keys-start-with-bytes-as-base64', base64_prefix,
152
+ 'as-json',
153
+ 'network-config', @network,
154
+ *block_args(block)
155
+ )
156
+ stdout
157
+ end
158
+ end # NEAR::CLI::Contract
@@ -0,0 +1,7 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ ##
4
+ # @see https://github.com/near/near-cli-rs/blob/main/docs/GUIDE.en.md#staking---Manage-staking-view-add-and-withdraw-stake
5
+ module NEAR::CLI::Staking
6
+ # TODO: implement the `NEAR::CLI::Staking` module.
7
+ end # NEAR::CLI::Staking
@@ -0,0 +1,70 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ ##
4
+ # @see https://github.com/near/near-cli-rs/blob/main/docs/GUIDE.en.md#tokens---Manage-token-assets-such-as-NEAR-FT-NFT
5
+ module NEAR::CLI::Tokens
6
+ ##
7
+ # Sends NEAR tokens from one account to another.
8
+ #
9
+ # @param [String] sender_id The account sending the tokens
10
+ # @param [String] receiver_id The account receiving the tokens
11
+ # @param [NEAR::Balance] amount The amount to send
12
+ # @return [Hash] Transaction result
13
+ def send_near(sender_id, receiver_id, amount)
14
+ raise ArgumentError, "amount must be a NEAR::Balance" unless amount.is_a?(NEAR::Balance)
15
+
16
+ _, stderr = execute(
17
+ 'tokens',
18
+ sender_id,
19
+ 'send-near', receiver_id, amount.to_cli_arg,
20
+ 'network-config', @network,
21
+ 'sign-with-keychain',
22
+ 'send'
23
+ )
24
+
25
+ # Extract transaction details from stderr:
26
+ if stderr.include?('Transaction sent')
27
+ tx_match = stderr.match(/Transaction ID: ([A-Za-z0-9]+)/)
28
+ tx_id = tx_match ? tx_match[1] : nil
29
+ {
30
+ success: true,
31
+ transaction_id: tx_id,
32
+ message: stderr.strip
33
+ }
34
+ else
35
+ {
36
+ success: false,
37
+ message: stderr.strip
38
+ }
39
+ end
40
+ end
41
+
42
+ ##
43
+ # Views the NEAR token balance of an account.
44
+ #
45
+ # @param [String] account_id The account to check
46
+ # @param [Block, Integer, String, Symbol] block The block to query (default: :now)
47
+ # @return [Hash] Balance information including available and total balance
48
+ def view_near_balance(account_id, block: :now)
49
+ _, stderr = execute(
50
+ 'tokens',
51
+ account_id,
52
+ 'view-near-balance',
53
+ 'network-config', @network,
54
+ *block_args(block)
55
+ )
56
+
57
+ # Parse the balance information from stderr:
58
+ available_match = stderr.match(/(\d+\.?\d*) NEAR available for transfer/)
59
+ total_match = stderr.match(/total balance is (\d+\.?\d*) NEAR/)
60
+ locked_match = stderr.match(/(\d+\.?\d*) NEAR is locked/)
61
+
62
+ {
63
+ account_id: account_id,
64
+ available_balance: available_match ? NEAR::Balance.from_near(available_match[1]) : nil,
65
+ total_balance: total_match ? NEAR::Balance.from_near(total_match[1]) : nil,
66
+ locked_balance: locked_match ? NEAR::Balance.from_near(locked_match[1]) : nil,
67
+ block: block,
68
+ }
69
+ end
70
+ end # NEAR::CLI::Tokens
@@ -0,0 +1,252 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ ##
4
+ # @see https://github.com/near/near-cli-rs/blob/main/docs/GUIDE.en.md#transaction---Operate-transactions
5
+ module NEAR::CLI::Transaction
6
+ ##
7
+ # Views status of a transaction.
8
+ #
9
+ # @param [String] tx_hash The transaction hash
10
+ # @return [Hash] Transaction status and details
11
+ def view_status(tx_hash)
12
+ stdout, _ = execute(
13
+ 'transaction',
14
+ 'view-status', tx_hash,
15
+ 'network-config', @network
16
+ )
17
+
18
+ # Parse the transaction details from the output
19
+ parse_transaction_status(stdout)
20
+ end
21
+
22
+ ##
23
+ # Reconstructs a CLI command from an existing transaction.
24
+ #
25
+ # @param [String] tx_hash The transaction hash
26
+ # @return [Hash] The reconstructed transaction details and CLI command
27
+ def reconstruct_transaction(tx_hash)
28
+ stdout, _ = execute(
29
+ 'transaction',
30
+ 'reconstruct-transaction', tx_hash,
31
+ 'network-config', @network
32
+ )
33
+
34
+ {
35
+ transaction: parse_transaction_reconstruction(stdout),
36
+ cli_command: extract_cli_command(stdout)
37
+ }
38
+ end
39
+
40
+ ##
41
+ # Constructs a new transaction with multiple actions.
42
+ #
43
+ # @param [String] signer_id Account that signs the transaction
44
+ # @param [String] receiver_id Account that receives the transaction
45
+ # @param [Array<Hash>] actions Array of action hashes, each containing :type and :args
46
+ # @return [String] Base64-encoded unsigned transaction
47
+ def construct_transaction(signer_id, receiver_id, actions)
48
+ args = [
49
+ 'transaction',
50
+ 'construct-transaction',
51
+ signer_id,
52
+ receiver_id
53
+ ]
54
+
55
+ actions.each do |action|
56
+ args += construct_action_args(action)
57
+ end
58
+
59
+ args += [
60
+ 'network-config', @network
61
+ ]
62
+
63
+ stdout, _ = execute(*args)
64
+ extract_unsigned_transaction(stdout)
65
+ end
66
+
67
+ ##
68
+ # Signs a previously prepared unsigned transaction.
69
+ #
70
+ # @param [String] unsigned_tx Base64-encoded unsigned transaction
71
+ # @param [Hash] options Signing options (e.g., :keychain, :ledger, :private_key)
72
+ # @return [String] Base64-encoded signed transaction
73
+ def sign_transaction(unsigned_tx, options = {})
74
+ args = [
75
+ 'transaction',
76
+ 'sign-transaction',
77
+ unsigned_tx,
78
+ 'network-config', @network
79
+ ]
80
+
81
+ args += case options[:method]
82
+ when :keychain
83
+ ['sign-with-keychain']
84
+ when :ledger
85
+ ['sign-with-ledger']
86
+ when :private_key
87
+ [
88
+ 'sign-with-plaintext-private-key',
89
+ options[:private_key]
90
+ ]
91
+ else
92
+ raise ArgumentError, "Invalid signing method: #{options[:method]}"
93
+ end
94
+
95
+ stdout, _ = execute(*args)
96
+ extract_signed_transaction(stdout)
97
+ end
98
+
99
+ ##
100
+ # Sends a signed transaction.
101
+ #
102
+ # @param [String] signed_tx Base64-encoded signed transaction
103
+ # @return [Hash] Transaction result
104
+ def send_signed_transaction(signed_tx)
105
+ stdout, stderr = execute(
106
+ 'transaction',
107
+ 'send-signed-transaction',
108
+ signed_tx,
109
+ 'network-config', @network
110
+ )
111
+
112
+ parse_transaction_result(stderr)
113
+ end
114
+
115
+ ##
116
+ # Sends a meta transaction (relayed transaction).
117
+ #
118
+ # @param [String] signed_tx Base64-encoded signed transaction
119
+ # @return [Hash] Transaction result
120
+ def send_meta_transaction(signed_tx)
121
+ stdout, stderr = execute(
122
+ 'transaction',
123
+ 'send-meta-transaction',
124
+ signed_tx,
125
+ 'network-config', @network
126
+ )
127
+
128
+ parse_transaction_result(stderr)
129
+ end
130
+
131
+ private
132
+
133
+ def parse_transaction_status(output)
134
+ # Parse the detailed transaction status output
135
+ # This would need to handle all the various fields from the transaction status
136
+ {
137
+ status: extract_status(output),
138
+ receipts: extract_receipts(output),
139
+ outcome: extract_outcome(output)
140
+ }
141
+ end
142
+
143
+ def parse_transaction_reconstruction(output)
144
+ # Parse the transaction reconstruction output
145
+ {
146
+ signer_id: extract_signer(output),
147
+ receiver_id: extract_receiver(output),
148
+ actions: extract_actions(output)
149
+ }
150
+ end
151
+
152
+ def construct_action_args(action)
153
+ case action[:type]
154
+ when :create_account
155
+ ['add-action', 'create-account']
156
+ when :transfer
157
+ ['add-action', 'transfer', action[:args][:amount].to_cli_arg]
158
+ when :add_key
159
+ construct_add_key_args(action[:args])
160
+ when :delete_key
161
+ ['add-action', 'delete-key', action[:args][:public_key]]
162
+ when :deploy
163
+ ['add-action', 'deploy', action[:args][:code_path]]
164
+ when :function_call
165
+ [
166
+ 'add-action', 'function-call',
167
+ action[:args][:method_name],
168
+ 'json-args', action[:args][:args].to_json,
169
+ '--prepaid-gas', action[:args][:gas],
170
+ '--attached-deposit', action[:args][:deposit].to_cli_arg
171
+ ]
172
+ else
173
+ raise ArgumentError, "Unknown action type: #{action[:type]}"
174
+ end
175
+ end
176
+
177
+ def construct_add_key_args(args)
178
+ base_args = ['add-action', 'add-key']
179
+
180
+ if args[:permission] == :full_access
181
+ base_args + ['grant-full-access']
182
+ else
183
+ base_args + [
184
+ 'grant-function-call-access',
185
+ '--allowance', args[:allowance].to_cli_arg,
186
+ '--receiver-account-id', args[:receiver_id],
187
+ '--method-names', Array(args[:method_names]).join(',')
188
+ ]
189
+ end + [
190
+ 'use-manually-provided-public-key', args[:public_key]
191
+ ]
192
+ end
193
+
194
+ def parse_transaction_result(output)
195
+ {
196
+ success: output.include?('Transaction sent'),
197
+ transaction_id: extract_transaction_id(output),
198
+ message: output
199
+ }
200
+ end
201
+
202
+ def extract_unsigned_transaction(output)
203
+ # Extract the base64 unsigned transaction from output
204
+ output[/Unsigned transaction: ([A-Za-z0-9+\/=]+)/, 1]
205
+ end
206
+
207
+ def extract_signed_transaction(output)
208
+ # Extract the base64 signed transaction from output
209
+ output[/Signed transaction: ([A-Za-z0-9+\/=]+)/, 1]
210
+ end
211
+
212
+ def extract_transaction_id(output)
213
+ output[/Transaction ID: ([A-Za-z0-9]+)/, 1]
214
+ end
215
+
216
+ def extract_cli_command(output)
217
+ output[/Here is your console command[^\n]*\n\s*(near.+)$/, 1]
218
+ end
219
+
220
+ # Additional helper methods for parsing transaction status output
221
+ def extract_status(output)
222
+ # Extract status from transaction status output
223
+ end
224
+
225
+ def extract_receipts(output)
226
+ # Extract receipts from transaction status output
227
+ end
228
+
229
+ def extract_outcome(output)
230
+ # Extract outcome from transaction status output
231
+ end
232
+
233
+ def extract_signer(output)
234
+ output[/signer_id:\s+(\S+)/, 1]
235
+ end
236
+
237
+ def extract_receiver(output)
238
+ output[/receiver_id:\s+(\S+)/, 1]
239
+ end
240
+
241
+ def extract_actions(output)
242
+ # Extract and parse actions list from output
243
+ actions = []
244
+ output.scan(/-- ([^:]+):\s+(.+)$/) do |type, details|
245
+ actions << {
246
+ type: type.strip.downcase.to_sym,
247
+ details: details.strip
248
+ }
249
+ end
250
+ actions
251
+ end
252
+ end # NEAR::CLI::Transaction
data/lib/near/cli.rb ADDED
@@ -0,0 +1,87 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'json'
4
+ require 'open3'
5
+
6
+ require_relative 'block'
7
+
8
+ class NEAR::CLI; end
9
+
10
+ require_relative 'cli/account'
11
+ require_relative 'cli/config'
12
+ require_relative 'cli/contract'
13
+ require_relative 'cli/staking'
14
+ require_relative 'cli/tokens'
15
+ require_relative 'cli/transaction'
16
+
17
+ class NEAR::CLI
18
+ NEAR_ENV = ENV['NEAR_ENV'] || 'testnet'
19
+
20
+ class Error < StandardError; end
21
+ class ProgramNotFoundError < Error; end
22
+ class ExecutionError < Error; end
23
+
24
+ def self.find_program
25
+ # First, check `$HOME/.cargo/bin/near`:
26
+ path = File.expand_path('~/.cargo/bin/near')
27
+ return path if File.executable?(path)
28
+
29
+ # Next, check `$PATH`:
30
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
31
+ path = File.join(path, 'near')
32
+ return path if File.executable?(path)
33
+ end
34
+
35
+ raise ProgramNotFoundError
36
+ end
37
+
38
+ ##
39
+ # @param [String, #to_s] path
40
+ # @param [String, #to_s] network
41
+ def initialize(path: self.class.find_program, network: NEAR_ENV)
42
+ @path, @network = path.to_s, network.to_s
43
+ end
44
+
45
+ ##
46
+ # @return [String]
47
+ def version
48
+ self.execute('--version').first.strip
49
+ end
50
+
51
+ include NEAR::CLI::Account
52
+ include NEAR::CLI::Tokens
53
+ include NEAR::CLI::Staking
54
+ include NEAR::CLI::Contract
55
+ include NEAR::CLI::Transaction
56
+ include NEAR::CLI::Config
57
+
58
+ private
59
+
60
+ ##
61
+ # @param [Array<String>] args
62
+ # @return [Array<String>]
63
+ def execute(*args)
64
+ command = [@path, *args.map(&:to_s)]
65
+ puts command.join(' ') if false
66
+ stdout, stderr, status = Open3.capture3(*command)
67
+
68
+ if status.success?
69
+ [stdout.strip, stderr.strip]
70
+ else
71
+ raise ExecutionError, "Command `#{command.join(' ')}` failed with exit code #{status.exitstatus}: #{stderr.strip}"
72
+ end
73
+ end
74
+
75
+ ##
76
+ # @param [Block, Integer, String, Symbol] block
77
+ def block_args(block)
78
+ block = case block
79
+ when :now then return ['now']
80
+ when NEAR::Block then block
81
+ when Integer then NEAR::Block.at_height(block)
82
+ when String then NEAR::Block.at_hash(block)
83
+ else raise "invalid block specifier: #{block.inspect}"
84
+ end
85
+ block.to_cli_args
86
+ end
87
+ end # NEAR::CLI
@@ -0,0 +1,21 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ ##
4
+ # Represents a NEAR transaction.
5
+ class NEAR::Transaction
6
+ ##
7
+ # @param [String, #to_s] hash
8
+ def initialize(hash)
9
+ @hash = hash.to_s
10
+ end
11
+
12
+ ##
13
+ # The transaction hash.
14
+ #
15
+ # @return [String]
16
+ attr_reader :hash
17
+
18
+ ##
19
+ # @return [String]
20
+ def to_s; @hash; end
21
+ end # NEAR::Transaction
@@ -0,0 +1 @@
1
+ # This is free and unencumbered software released into the public domain.
data/lib/near.rb ADDED
@@ -0,0 +1,10 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ module NEAR; end
4
+
5
+ require_relative 'near/account'
6
+ require_relative 'near/balance'
7
+ require_relative 'near/block'
8
+ require_relative 'near/cli'
9
+ require_relative 'near/transaction'
10
+ require_relative 'near/version'
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: near
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Arto Bendiken
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-01-19 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rspec
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.12'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.12'
26
+ - !ruby/object:Gem::Dependency
27
+ name: yard
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.9'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.9'
40
+ description: A Ruby client library for the NEAR Protocol.
41
+ email: arto@bendiken.net
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - AUTHORS
47
+ - CHANGES.md
48
+ - README.md
49
+ - UNLICENSE
50
+ - VERSION
51
+ - lib/near.rb
52
+ - lib/near/account.rb
53
+ - lib/near/balance.rb
54
+ - lib/near/block.rb
55
+ - lib/near/cli.rb
56
+ - lib/near/cli/account.rb
57
+ - lib/near/cli/config.rb
58
+ - lib/near/cli/contract.rb
59
+ - lib/near/cli/staking.rb
60
+ - lib/near/cli/tokens.rb
61
+ - lib/near/cli/transaction.rb
62
+ - lib/near/transaction.rb
63
+ - lib/near/version.rb
64
+ homepage: https://github.com/dryruby/near.rb
65
+ licenses:
66
+ - Unlicense
67
+ metadata:
68
+ bug_tracker_uri: https://github.com/dryruby/near.rb/issues
69
+ changelog_uri: https://github.com/dryruby/near.rb/blob/master/CHANGES.md
70
+ documentation_uri: https://rubydoc.info/gems/near
71
+ homepage_uri: https://github.com/dryruby/near.rb
72
+ source_code_uri: https://github.com/dryruby/near.rb
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '3.0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.6.2
88
+ specification_version: 4
89
+ summary: 'NEAR.rb: NEAR for Ruby'
90
+ test_files: []