vtiger-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7fc43fdf6a0d5af0bff7a7c986152c32be237eff204925eca7afee5964f2e053
4
+ data.tar.gz: d1a2942949716e03e712701982c1135ac0deb6b9968cde6e9f9a2f9d189ff72a
5
+ SHA512:
6
+ metadata.gz: c88c64e9234f5705cbf153f60254793522cf3523617df8e42d4e30dba71f8dd01f327b7cf8e066efb033c3740cb4306c6e23715109251aa26ea31922a69cef1d
7
+ data.tar.gz: 1e4fb05bf0ed48ff2d580b35845cac1c812d66202b04566a82c6a6a7487540c9df9ccc044bebf886ba9430839b3797afc1dd759080db0abdb4286f2ef58f971a
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'pry-byebug'
7
+ gem 'rake', '~> 12.0'
8
+ gem 'rubocop', '~> 0.90'
9
+ gem 'webmock', '~> 3.9', '>= 3.9.1'
10
+ end
@@ -0,0 +1,81 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vtiger-ruby (0.1.0)
5
+ faraday (~> 1.0.1)
6
+ json (~> 2.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.7.0)
12
+ public_suffix (>= 2.0.2, < 5.0)
13
+ ast (2.4.1)
14
+ byebug (11.1.3)
15
+ coderay (1.1.3)
16
+ crack (0.4.4)
17
+ diff-lcs (1.4.4)
18
+ faraday (1.0.1)
19
+ multipart-post (>= 1.2, < 3)
20
+ hashdiff (1.0.1)
21
+ json (2.3.1)
22
+ method_source (1.0.0)
23
+ multipart-post (2.1.1)
24
+ parallel (1.19.2)
25
+ parser (2.7.1.4)
26
+ ast (~> 2.4.1)
27
+ pry (0.13.1)
28
+ coderay (~> 1.1)
29
+ method_source (~> 1.0)
30
+ pry-byebug (3.9.0)
31
+ byebug (~> 11.0)
32
+ pry (~> 0.13.0)
33
+ public_suffix (4.0.6)
34
+ rainbow (3.0.0)
35
+ rake (12.3.3)
36
+ regexp_parser (1.7.1)
37
+ rexml (3.2.4)
38
+ rspec (3.9.0)
39
+ rspec-core (~> 3.9.0)
40
+ rspec-expectations (~> 3.9.0)
41
+ rspec-mocks (~> 3.9.0)
42
+ rspec-core (3.9.2)
43
+ rspec-support (~> 3.9.3)
44
+ rspec-expectations (3.9.2)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-mocks (3.9.1)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.9.0)
50
+ rspec-support (3.9.3)
51
+ rubocop (0.90.0)
52
+ parallel (~> 1.10)
53
+ parser (>= 2.7.1.1)
54
+ rainbow (>= 2.2.2, < 4.0)
55
+ regexp_parser (>= 1.7)
56
+ rexml
57
+ rubocop-ast (>= 0.3.0, < 1.0)
58
+ ruby-progressbar (~> 1.7)
59
+ unicode-display_width (>= 1.4.0, < 2.0)
60
+ rubocop-ast (0.4.0)
61
+ parser (>= 2.7.1.4)
62
+ ruby-progressbar (1.10.1)
63
+ unicode-display_width (1.7.0)
64
+ webmock (3.9.1)
65
+ addressable (>= 2.3.6)
66
+ crack (>= 0.3.2)
67
+ hashdiff (>= 0.4.0, < 2.0.0)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ pry-byebug
74
+ rake (~> 12.0)
75
+ rspec (~> 3.9)
76
+ rubocop (~> 0.90)
77
+ vtiger-ruby!
78
+ webmock (~> 3.9, >= 3.9.1)
79
+
80
+ BUNDLED WITH
81
+ 2.1.4
@@ -0,0 +1,102 @@
1
+ # VtigerRuby
2
+
3
+ VtigerRuby is a Ruby SDK for the Vtiger CRM API.
4
+
5
+ Official documentation of the Vtiger API can be found here:
6
+
7
+ 1. [Vtiger REST API Docs](https://www.vtiger.com/docs/rest-api-for-vtiger)
8
+ 2. [Vtiger Third Party Integrations](https://community.vtiger.com/help/vtigercrm/developers/third-party-app-integration.html)
9
+
10
+ ## Getting Started
11
+
12
+ * Retrieve your `Accesskey` token information from the `My Preferences` page in the CRM Web UI.
13
+ * `username` information used when signing into your instance of the CRM.
14
+ * `endpoint` url specific to your instance, eg: https://your_instance.odx.vtiger.com/restapi/v1/vtiger/default
15
+
16
+ > Installation information coming soon...
17
+
18
+ ### Creating a Client
19
+
20
+ ```ruby
21
+ require 'vtiger-ruby'
22
+ ```
23
+
24
+ ```ruby
25
+ endpoint = ENV['VTIGER_ENDPOINT']
26
+ username = ENV['VTIGER_USERNAME']
27
+ accesskey = ENV['VTIGER_ACCESSS_KEY']
28
+ ```
29
+
30
+ ```ruby
31
+ client = VtigerRuby::Client.new(
32
+ endpoint: endpoint,
33
+ username: username,
34
+ accesskey: accesskey
35
+ )
36
+ ```
37
+
38
+ ### Authentication
39
+
40
+ Vtiger API Authentication happens in two steps:
41
+
42
+ 1. Request the challenge token
43
+ ```ruby
44
+ client.get_challenge
45
+ ```
46
+
47
+ 2. Login request
48
+ ```ruby
49
+ client.login
50
+ ```
51
+
52
+ Alternatively, you can authenticate the client using the `connect` method.
53
+ This single method call negates the need to complete `step 1` & `step 2` listed above.
54
+ ```ruby
55
+ client.connect
56
+ ```
57
+
58
+ ## Models
59
+
60
+ The SDK arranges default [Vtiger CRM Modules](https://www.vtiger.com/docs/rest-api-for-vtiger#/CRM_Modules) into `model` classes.
61
+ The model class can then be used to perform operations against the corresponding Vtiger module.
62
+
63
+ ### Account
64
+
65
+ ```ruby
66
+ client.account.all # Retrieves all Vtiger Account module records
67
+ ```
68
+
69
+ You can also retrieve all Vtiger Account module records from the `VtigerRuby::Account` model.
70
+
71
+ ```ruby
72
+ VtigerRuby::Account.class_config(client) # Configures the class with client model
73
+ VtigerRuby::Account.all # Retrieves all Vtiger Account module records
74
+ ```
75
+
76
+ ## Example
77
+
78
+ ```ruby
79
+ require 'vtiger-ruby'
80
+
81
+ # Credential information specific to vtiger instance
82
+ endpoint = ENV['VTIGER_ENDPOINT']
83
+ username = ENV['VTIGER_USERNAME']
84
+ accesskey = ENV['VTIGER_ACCESSS_KEY']
85
+
86
+ # Initializes the VtigerRuby client
87
+ client = VtigerRuby::Client.new(
88
+ endpoint: endpoint,
89
+ username: username,
90
+ accesskey: accesskey
91
+ )
92
+
93
+ # Requests Vtiger challenge token and login
94
+ client.connect
95
+
96
+ # Retrieves all account records from the Account module
97
+ accounts = client.account.all
98
+ ```
99
+
100
+ ## Code Status
101
+
102
+ [![Maintainability](https://api.codeclimate.com/v1/badges/25a5fa53236293d044d8/maintainability)](https://codeclimate.com/github/ymukmar/vtiger-ruby/maintainability) [![Build Status](https://travis-ci.com/ymukmar/vtiger-ruby.svg?branch=main)](https://travis-ci.com/ymukmar/vtiger-ruby)
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,12 @@
1
+ require 'vtiger-ruby/version'
2
+ require 'vtiger-ruby/client'
3
+
4
+ require 'vtiger-ruby/api/query'
5
+
6
+ require 'vtiger-ruby/models/vtiger_model'
7
+ require 'vtiger-ruby/models/account'
8
+
9
+ module VtigerRuby
10
+ class << self
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ module VtigerRuby
2
+ module Api
3
+ class Query
4
+ def initialize(client, sql_query: nil)
5
+ @sql_query = sql_query
6
+ @client = client
7
+ end
8
+
9
+ def fetch_all
10
+ result = []
11
+ latest_fetch = fetch
12
+
13
+ until latest_fetch.empty?
14
+ result.concat(latest_fetch)
15
+ latest_fetch = fetch
16
+ end
17
+ result
18
+ end
19
+
20
+ def fetch(sql_query = nil)
21
+ params = {
22
+ 'operation': 'query',
23
+ 'sessionName': @client.session_id,
24
+ 'query': sql_query || sql_for_records_after(last_record_id)
25
+ }
26
+
27
+ @query_response = Faraday.get(@client.endpoint, params) do |req|
28
+ req.headers['User-Agent'] = 'VtigerRuby'
29
+ end
30
+
31
+ JSON.parse(@query_response.body).dig('result')
32
+ end
33
+
34
+ private
35
+ def sql_for_records_after(record_id)
36
+ <<-SQL
37
+ #{@sql_query.gsub(':record_filter_clause', "id > #{record_id};")}
38
+ SQL
39
+ end
40
+
41
+ def last_record_id
42
+ response = @query_response.dup
43
+
44
+ unless response.nil? || (response = JSON.parse(response.body).dig('result')).empty?
45
+ response.last.dig('id')
46
+ else
47
+ # returns first N records where N <= 200 records
48
+ 'x0'
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,80 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module VtigerRuby
5
+ class Client
6
+ attr_accessor :endpoint, :username, :accesskey, :session_id
7
+
8
+ def initialize(endpoint: nil, username: nil, accesskey: nil)
9
+ @endpoint = endpoint
10
+ @username = username
11
+ @accesskey = accesskey
12
+ end
13
+
14
+ def get_challenge
15
+ challenge_params = { operation: 'getchallenge', username: username }
16
+
17
+ response = Faraday.get(endpoint, challenge_params) do |req|
18
+ req.headers['User-Agent'] = 'VtigerRuby'
19
+ end
20
+
21
+ body = JSON.parse(response.body)
22
+ @token = body['result']['token']
23
+
24
+ body
25
+ end
26
+
27
+ def login
28
+ login_params = {
29
+ 'operation': 'login',
30
+ 'username': username,
31
+ 'accessKey': md5_token
32
+ }
33
+
34
+ response = Faraday.post(endpoint) do |req|
35
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
36
+ req.headers['User-Agent'] = 'VtigerRuby'
37
+ req.body = login_params
38
+ end
39
+
40
+ body = JSON.parse(response.body)
41
+ @session_id = body['result']['sessionName']
42
+
43
+ body
44
+ end
45
+
46
+ def connect
47
+ get_challenge
48
+ login
49
+ end
50
+
51
+ def logout
52
+ logout_params = {
53
+ 'operation': 'logout',
54
+ 'sessionName': @session_id
55
+ }
56
+
57
+ response = Faraday.post(endpoint) do |req|
58
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
59
+ req.headers['User-Agent'] = 'VtigerRuby'
60
+ req.body = logout_params
61
+ end
62
+
63
+ remove_instance_variable(:@token)
64
+ remove_instance_variable(:@session_id)
65
+ remove_instance_variable(:@md5_token)
66
+
67
+ JSON.parse(response.body)
68
+ end
69
+
70
+ def account
71
+ VtigerRuby::Account.class_config(self)
72
+ VtigerRuby::Account
73
+ end
74
+
75
+ private
76
+ def md5_token
77
+ @md5_token ||= Digest::MD5.hexdigest(@token + accesskey)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,13 @@
1
+ module VtigerRuby
2
+ class Account < VtigerModel
3
+ VTIGER_MODULE = 'Accounts'.freeze
4
+
5
+ def self.all
6
+ all_from_vtiger(self, 'select * from Accounts where :record_filter_clause')
7
+ end
8
+
9
+ def self.fetch(sql_query = nil)
10
+ fetch_from_vtiger(self, sql_query)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ module VtigerRuby
2
+ class VtigerModel
3
+ def self.class_config(client)
4
+ @@client = client
5
+ end
6
+
7
+ def self.all_from_vtiger(klass, sql_query)
8
+ VtigerRuby::Api::Query
9
+ .new(@@client, sql_query: sql_query)
10
+ .fetch_all
11
+ .reduce([]) do |memo, data|
12
+ memo << klass.new(@@client, data)
13
+ end
14
+ end
15
+
16
+ def self.fetch_from_vtiger(klass, sql_query)
17
+ VtigerRuby::Api::Query
18
+ .new(@@client)
19
+ .fetch(sql_query)
20
+ .reduce([]) do |memo, data|
21
+ memo << klass.new(@@client, data)
22
+ end
23
+ end
24
+
25
+ def initialize(client, attribs = {})
26
+ @client = client
27
+ self.attributes = attribs unless attribs.empty?
28
+ end
29
+
30
+ attr_accessor :fetch_response
31
+
32
+ def attributes=(hash)
33
+ @fetch_response = hash
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module VtigerRuby
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe VtigerRuby do
4
+ it 'returns the current version number' do
5
+ expect(VtigerRuby::VERSION).to eq('0.1.0')
6
+ end
7
+ end
@@ -0,0 +1,42 @@
1
+ require 'vtiger-ruby'
2
+ require 'webmock/rspec'
3
+
4
+ VTIGER_API_RESPONSE = {
5
+ challenge: {
6
+ "success": true,
7
+ "result": {
8
+ "token": 'test_token',
9
+ "serverTime": 1599816377,
10
+ "expireTime": 1599816677
11
+ }
12
+ },
13
+ login: {
14
+ "success": true,
15
+ "result": {
16
+ "sessionName": 'test_session_id',
17
+ "userId": '19x101',
18
+ "version": '0.22',
19
+ "vtigerVersion": '7.20.9.1'
20
+ }
21
+ }
22
+ }
23
+
24
+ RSpec.configure do |config|
25
+ config.expect_with :rspec do |c|
26
+ c.include_chain_clauses_in_custom_matcher_descriptions = true
27
+ end
28
+
29
+ config.mock_with :rspec do |mocks|
30
+ mocks.verify_partial_doubles = true
31
+ end
32
+
33
+ config.before(:each) do
34
+ stub_request(:get, /your_instance.odx.vtiger.com/).
35
+ to_return(status: 200, body: VTIGER_API_RESPONSE[:challenge].to_json)
36
+
37
+ stub_request(:post, /your_instance.odx.vtiger.com/).
38
+ to_return(status: 200, body: VTIGER_API_RESPONSE[:login].to_json)
39
+ end
40
+ end
41
+
42
+ WebMock.disable_net_connect!(allow_localhost: true)
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe VtigerRuby::Client do
4
+ let(:endpoint) { 'https://your_instance.odx.vtiger.com/webservice.php?' }
5
+ let(:username) { 'test@example.com' }
6
+ let(:accesskey) { 'testAccessKey' }
7
+ let(:client) { described_class.new(endpoint: endpoint, username: username, accesskey: accesskey) }
8
+
9
+ describe 'get_challenge' do
10
+ it 'sets @token' do
11
+ expected = VTIGER_API_RESPONSE[:challenge][:result][:token]
12
+
13
+ client.get_challenge
14
+
15
+ expect(client.instance_variable_get(:@token)).to eq(expected)
16
+ end
17
+ end
18
+
19
+ describe 'login' do
20
+ it 'sets @session_id and @md5_token' do
21
+ token = VTIGER_API_RESPONSE[:challenge][:result][:token]
22
+ expected = VTIGER_API_RESPONSE[:login][:result][:sessionName]
23
+ md5_token = Digest::MD5.hexdigest(token + accesskey)
24
+
25
+ client.instance_variable_set(:@token, token)
26
+ client.login
27
+
28
+ expect(client.instance_variable_get(:@session_id)).to eq(expected)
29
+ expect(client.instance_variable_get(:@md5_token)).to eq(md5_token)
30
+ end
31
+ end
32
+
33
+ describe 'connect' do
34
+ it 'sets @token, @md5_token and @session_id' do
35
+ token = VTIGER_API_RESPONSE[:challenge][:result][:token]
36
+ session_id = VTIGER_API_RESPONSE[:login][:result][:sessionName]
37
+ md5_token = Digest::MD5.hexdigest(token + accesskey)
38
+
39
+ client.connect
40
+
41
+ expect(client.instance_variable_get(:@session_id)).to eq(session_id)
42
+ expect(client.instance_variable_get(:@token)).to eq(token)
43
+ expect(client.instance_variable_get(:@md5_token)).to eq(md5_token)
44
+ end
45
+ end
46
+
47
+ describe 'logout' do
48
+ it 'unsets @token' do
49
+ token = VTIGER_API_RESPONSE[:challenge][:result][:token]
50
+
51
+ client.connect
52
+
53
+ expect { client.logout }
54
+ .to change { client.instance_variable_get(:@token) }
55
+ .from(token)
56
+ .to(nil)
57
+ end
58
+
59
+ it 'unsets @session_id' do
60
+ session_id = VTIGER_API_RESPONSE[:login][:result][:sessionName]
61
+
62
+ client.connect
63
+
64
+ expect { client.logout }
65
+ .to change { client.instance_variable_get(:@session_id) }
66
+ .from(session_id)
67
+ .to(nil)
68
+ end
69
+
70
+ it 'unsets @md5_token' do
71
+ token = VTIGER_API_RESPONSE[:challenge][:result][:token]
72
+ md5_token = Digest::MD5.hexdigest(token + accesskey)
73
+
74
+ client.connect
75
+
76
+ expect { client.logout }
77
+ .to change { client.instance_variable_get(:@md5_token) }
78
+ .from(md5_token)
79
+ .to(nil)
80
+ end
81
+ end
82
+
83
+ describe 'account' do
84
+ it 'sets the client as a class object and returns the account class' do
85
+ client.connect
86
+
87
+ expect(client.account.class_variable_get(:@@client)).to eq(client)
88
+ expect(client.account.class_variable_get(:@@client)).to be_a(VtigerRuby::Client)
89
+ expect(client.account).to eq(VtigerRuby::Account)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'lib/vtiger-ruby/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'vtiger-ruby'
5
+ spec.version = VtigerRuby::VERSION
6
+ spec.authors = ["Yedidia Muk'mar"]
7
+ spec.summary = 'Vtiger API Ruby SDK'
8
+ spec.description = 'Vtiger API Library for Ruby applications'
9
+ spec.homepage = 'https://github.com/ymukmar/vtiger-ruby'
10
+
11
+ spec.required_ruby_version = '>= 2.5.1'
12
+
13
+ spec.add_runtime_dependency 'faraday', '~> 1.0.1'
14
+ spec.add_runtime_dependency 'json', '~> 2.3'
15
+ spec.add_development_dependency 'rspec', '~> 3.9'
16
+ spec.add_development_dependency 'webmock', '~> 3.9'
17
+
18
+ spec.files = `find *`.split("\n").uniq.sort
19
+ spec.executables = []
20
+ spec.require_paths = ['lib']
21
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vtiger-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yedidia Muk'mar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-10-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.9'
69
+ description: Vtiger API Library for Ruby applications
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - Gemfile
76
+ - Gemfile.lock
77
+ - README.md
78
+ - Rakefile
79
+ - lib/vtiger-ruby.rb
80
+ - lib/vtiger-ruby/api/query.rb
81
+ - lib/vtiger-ruby/client.rb
82
+ - lib/vtiger-ruby/models/account.rb
83
+ - lib/vtiger-ruby/models/vtiger_model.rb
84
+ - lib/vtiger-ruby/version.rb
85
+ - spec/quality_spec.rb
86
+ - spec/spec_helper.rb
87
+ - spec/vtiger-ruby/client_spec.rb
88
+ - spec/vtiger-ruby/models/account_spec.rb
89
+ - spec/vtiger-ruby/models/vtiger_model_spec.rb
90
+ - vtiger-ruby.gemspec
91
+ homepage: https://github.com/ymukmar/vtiger-ruby
92
+ licenses: []
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 2.5.1
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.7.7
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Vtiger API Ruby SDK
114
+ test_files: []