zoho_hub 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -8
  3. data/README.md +160 -13
  4. data/bin/console +4 -0
  5. data/bin/read +8 -4
  6. data/bin/zoho_hub +29 -48
  7. data/examples/models/campaign.rb +13 -0
  8. data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/potential.rb +2 -1
  9. data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/quote.rb +5 -9
  10. data/lib/zoho_hub/auth.rb +36 -28
  11. data/lib/zoho_hub/base_record.rb +23 -12
  12. data/lib/zoho_hub/cli/callback_server.rb +94 -0
  13. data/lib/zoho_hub/cli/read_modules.rb +122 -0
  14. data/lib/zoho_hub/connection.rb +7 -0
  15. data/lib/zoho_hub/oauth_callback_server.rb +0 -4
  16. data/lib/zoho_hub/{module_builder.rb → reflection/module_builder.rb} +11 -15
  17. data/lib/zoho_hub/response.rb +1 -5
  18. data/lib/zoho_hub/string_utils.rb +5 -1
  19. data/lib/zoho_hub/validations/base_validation.rb +14 -0
  20. data/lib/zoho_hub/validations/validate_length.rb +19 -0
  21. data/lib/zoho_hub/validations/validate_picklist.rb +22 -0
  22. data/lib/zoho_hub/version.rb +1 -1
  23. data/lib/zoho_hub/views/variables.erb +7 -0
  24. data/lib/zoho_hub/with_connection.rb +8 -0
  25. data/lib/zoho_hub/with_validations.rb +66 -0
  26. data/lib/zoho_hub.rb +2 -1
  27. metadata +12 -10
  28. data/lib/zoho_hub/deprecated_and_only_for_reference_records/account.rb +0 -43
  29. data/lib/zoho_hub/deprecated_and_only_for_reference_records/campaign.rb +0 -14
  30. data/lib/zoho_hub/deprecated_and_only_for_reference_records/contact.rb +0 -45
  31. data/lib/zoho_hub/deprecated_and_only_for_reference_records/funder.rb +0 -9
  32. data/lib/zoho_hub/deprecated_and_only_for_reference_records/product.rb +0 -9
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'launchy'
4
+ require 'optparse'
5
+
6
+ require 'zoho_hub'
7
+ require 'zoho_hub/oauth_callback_server'
8
+
9
+ module ZohoHub
10
+ module Cli
11
+ class CallbackServer
12
+ def initialize
13
+ @options = {}
14
+ end
15
+
16
+ def parser
17
+ @parser ||= OptionParser.new do |op|
18
+ op.banner = "Usage: #{op.program_name} server -c CLIENT_ID -s SECRET [options]"
19
+
20
+ op.on('-c', '--client-id=client_id', 'The Zoho client ID') do |client|
21
+ @options[:client_id] = client
22
+ end
23
+
24
+ op.on('-s', '--secret=secret', 'The Zoho secret') do |secret|
25
+ @options[:secret] = secret
26
+ end
27
+
28
+ op.on('-p', '--port=port', "The port for your callback (#{default_port})") do |port|
29
+ @options[:port] = port
30
+ end
31
+ end
32
+ end
33
+
34
+ def default_port
35
+ ZohoHub::OauthCallbackServer.settings.port
36
+ end
37
+
38
+ def run(argv = ARGV, env = ENV)
39
+ exit 1 unless good_run(argv, env)
40
+
41
+ ZohoHub::OauthCallbackServer.set(:port, @options[:port]) if @options[:port]
42
+
43
+ callback_path = ZohoHub::OauthCallbackServer::CALLBACK_PATH
44
+ bind_port = ZohoHub::OauthCallbackServer.settings.port
45
+ bind_address = ZohoHub::OauthCallbackServer.settings.bind
46
+
47
+ callback_url = "http://#{bind_address}:#{bind_port}/#{callback_path}"
48
+
49
+ ZohoHub.configure do |config|
50
+ config.client_id = @options[:client_id] || ENV['ZOHO_CLIENT_ID']
51
+ config.secret = @options[:secret] || ENV['ZOHO_SECRET']
52
+ config.redirect_uri = callback_url
53
+ end
54
+
55
+ if configuration_incomplete?
56
+ parser.parse %w[--help]
57
+ exit 1
58
+ end
59
+
60
+ puts "Callback URL: #{callback_url}"
61
+
62
+ url = ZohoHub::Auth.auth_url
63
+ Launchy.open(url)
64
+
65
+ puts "Running callback server...."
66
+ ZohoHub::OauthCallbackServer.run!
67
+ end
68
+
69
+ def configuration_incomplete?
70
+ !ZohoHub.configuration.client_id || !ZohoHub.configuration.secret
71
+ end
72
+
73
+ def good_run(argv, env)
74
+ return false unless parse(argv, env)
75
+
76
+ true
77
+ end
78
+
79
+ def parse(argv, _env)
80
+ parser.parse!(argv)
81
+ true
82
+ rescue OptionParser::ParseError => error
83
+ error_output(error)
84
+ end
85
+
86
+ def error_output(error)
87
+ $stderr.puts "Error: #{error}"
88
+ $stderr.puts "Try `#{parser.program_name} server --help' for more information"
89
+
90
+ false
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'fileutils'
5
+ require 'json'
6
+
7
+ require 'zoho_hub'
8
+ require 'zoho_hub/settings/module'
9
+
10
+ module ZohoHub
11
+ module Cli
12
+ class ReadModules
13
+ def initialize
14
+ @options = {}
15
+ end
16
+
17
+ def parser
18
+ @parser ||= OptionParser.new do |op|
19
+ op.banner = "Usage: #{op.program_name} read-modules -c CLIENT_ID -s SECRET"
20
+
21
+ op.on('-c', '--client-id=client_id', 'The Zoho client ID') do |client|
22
+ @options[:client_id] = client
23
+ end
24
+
25
+ op.on('-s', '--secret=secret', 'The Zoho secret') do |secret|
26
+ @options[:secret] = secret
27
+ end
28
+
29
+ op.on('-r', '--refresh-token=token', 'Your refresh token') do |refresh|
30
+ @options[:refresh_token] = refresh
31
+ end
32
+ end
33
+ end
34
+
35
+ def run(argv = ARGV, env = ENV)
36
+ exit 1 unless good_run(argv, env)
37
+
38
+ setup_connection
39
+
40
+ client_id = @options[:client_id] || ENV['ZOHO_CLIENT_ID']
41
+ puts "Reading modules for client ID: #{client_id}..."
42
+
43
+ modules_hashes = ZohoHub::Settings::Module.all_json
44
+
45
+ puts "Found #{modules_hashes.size} modules"
46
+
47
+ modules_hashes.each do |hash|
48
+ puts "- Caching configuration for #{hash[:plural_label]}"
49
+ cache_module_info(hash)
50
+ end
51
+ end
52
+
53
+ def good_run(argv, env)
54
+ return false unless parse(argv, env)
55
+
56
+ true
57
+ end
58
+
59
+ def setup_connection
60
+ ZohoHub.configure do |config|
61
+ config.client_id = @options[:client_id] || ENV['ZOHO_CLIENT_ID']
62
+ config.secret = @options[:secret] || ENV['ZOHO_SECRET']
63
+ end
64
+
65
+ refresh_token = @options[:refresh_token] || ENV['ZOHO_REFRESH_TOKEN']
66
+ token_params = ZohoHub::Auth.refresh_token(refresh_token)
67
+
68
+ if configuration_incomplete?(refresh_token)
69
+ parser.parse %w[--help]
70
+ exit 1
71
+ end
72
+
73
+ ZohoHub.setup_connection(token_params)
74
+ end
75
+
76
+ def configuration_incomplete?(refresh_token)
77
+ return true unless refresh_token
78
+
79
+ !ZohoHub.configuration.client_id || !ZohoHub.configuration.secret
80
+ end
81
+
82
+ def cache_module_info(info)
83
+ modules_path = File.join(ZohoHub.root, 'cache', 'modules')
84
+ FileUtils.mkdir_p(modules_path)
85
+ file_name = File.join(modules_path, "#{info[:api_name]}.json")
86
+
87
+ File.open(file_name, 'w') do |file|
88
+ file.write(JSON.pretty_generate(info))
89
+ end
90
+
91
+ return unless info[:api_supported]
92
+
93
+ cache_module_fields(info)
94
+ end
95
+
96
+ def cache_module_fields(info)
97
+ fields_array = ZohoHub::Settings::Field.all_json_for(info[:api_name])
98
+ fields_path = File.join(ZohoHub.root, 'cache', 'fields')
99
+ FileUtils.mkdir_p(fields_path)
100
+ file_name = File.join(fields_path, "#{info[:api_name]}.json")
101
+
102
+ File.open(file_name, 'w') do |file|
103
+ file.write(JSON.pretty_generate(fields_array))
104
+ end
105
+ end
106
+
107
+ def parse(argv, _env)
108
+ parser.parse!(argv)
109
+ true
110
+ rescue OptionParser::ParseError => error
111
+ error_output(error)
112
+ end
113
+
114
+ def error_output(error)
115
+ $stderr.puts "Error: #{error}"
116
+ $stderr.puts "Try `#{parser.program_name} server --help' for more information"
117
+
118
+ false
119
+ end
120
+ end
121
+ end
122
+ end
@@ -47,6 +47,13 @@ module ZohoHub
47
47
  response.body
48
48
  end
49
49
 
50
+ def delete(path, params = {})
51
+ log "DELETE #{path} with #{params}"
52
+
53
+ response = with_refresh { adapter.delete(path, params) }
54
+ response.body
55
+ end
56
+
50
57
  def access_token?
51
58
  @access_token
52
59
  end
@@ -8,10 +8,6 @@ module ZohoHub
8
8
 
9
9
  CALLBACK_PATH = 'oauth2callback'
10
10
 
11
- before do
12
- content_type :json
13
- end
14
-
15
11
  get "/#{CALLBACK_PATH}" do
16
12
  grant_token = params[:code]
17
13
 
@@ -9,7 +9,7 @@ module ZohoHub
9
9
  cached_module_definitions.map do |file|
10
10
  json = MultiJson.load(File.read(file), symbolize_keys: true)
11
11
 
12
- create_module(json)
12
+ eval_module_class(json)
13
13
  end
14
14
  end
15
15
 
@@ -17,31 +17,27 @@ module ZohoHub
17
17
  Dir[File.join(ZohoHub.root, 'cache', 'modules', '**')]
18
18
  end
19
19
 
20
- def create_module(json)
20
+ def eval_module_class(json)
21
21
  fields = cached_module_fields(json[:api_name])
22
22
 
23
23
  klass = Class.new(ZohoHub::BaseRecord) do
24
24
  request_path json[:api_name]
25
25
 
26
- translations = {}
26
+ translations = { id: :id }
27
27
  fields.each do |field|
28
- key = StringUtils.underscore(field[:api_name])
28
+ key = StringUtils.underscore(field[:api_name]).to_sym
29
29
 
30
- translations[key] = field[:api_name]
31
- end
32
-
33
- if translations.any?
34
- attributes(*translations.keys)
35
- attribute_translation(translations)
36
- end
30
+ translations[key] = field[:api_name].to_sym
37
31
 
38
- def initialize(params)
39
- attributes.each do |attr|
40
- zoho_key = attr_to_zoho_key(attr)
32
+ add_validation(key, validate: :length, length: field[:length]) if field[:length]
41
33
 
42
- send("#{attr}=", params[zoho_key] || params[attr])
34
+ if field[:data_type] == 'picklist'
35
+ add_validation(key, validate: :picklist, list: field[:pick_list_values])
43
36
  end
44
37
  end
38
+
39
+ attributes(*translations.keys)
40
+ attribute_translation(translations)
45
41
  end
46
42
 
47
43
  ZohoHub.const_set(StringUtils.camelize(json[:singular_label]), klass)
@@ -31,11 +31,7 @@ module ZohoHub
31
31
 
32
32
  def data
33
33
  data = @params[:data] if @params.dig(:data)
34
- data ||= @params
35
-
36
- return data.first if data.is_a?(Array) && data.size == 1
37
-
38
- data
34
+ data || @params
39
35
  end
40
36
 
41
37
  def msg
@@ -8,7 +8,11 @@ module ZohoHub
8
8
  end
9
9
 
10
10
  def pluralize(text)
11
- "#{text}s"
11
+ if ENV.key?('RAILS_ENV')
12
+ ActiveSupport::Inflector.pluralize(text)
13
+ else
14
+ "#{text}s"
15
+ end
12
16
  end
13
17
 
14
18
  def camelize(text)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZohoHub
4
+ module Validations
5
+ class BaseValidation
6
+ attr_accessor :record, :field
7
+
8
+ def initialize(record, field)
9
+ @record = record
10
+ @field = field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zoho_hub/validations/base_validation'
4
+
5
+ module ZohoHub
6
+ module Validations
7
+ class ValidateLength < BaseValidation
8
+ def validate(options = {})
9
+ value = record.send(field)
10
+
11
+ return unless value
12
+
13
+ return if value.size <= options[:length]
14
+
15
+ record.add_error(field, 'is too long')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zoho_hub/validations/base_validation'
4
+
5
+ module ZohoHub
6
+ module Validations
7
+ class ValidatePicklist < BaseValidation
8
+ def validate(options = {})
9
+ value = record.send(field)
10
+
11
+ return unless value
12
+
13
+ list = options[:list].map { |option| option[:actual_value] }
14
+
15
+ return if list.include?(value)
16
+
17
+ msg = "has an invalid value `#{value}`. Accepted values: #{list.join(', ')}"
18
+ record.add_error(field, msg)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZohoHub
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -38,6 +38,11 @@
38
38
  padding: 0;
39
39
  margin: 0;
40
40
  }
41
+
42
+ footer {
43
+ margin-top: 60px;
44
+ font-size: .8em;
45
+ }
41
46
  </style>
42
47
  </head>
43
48
 
@@ -68,5 +73,7 @@
68
73
  config.refresh_token = ENV['ZOHO_REFRESH_TOKEN']
69
74
  end</code></pre>
70
75
  </div>
76
+
77
+ <footer>ZohoHub <%= ZohoHub::VERSION %></footer>
71
78
  </body>
72
79
  </html>
@@ -19,6 +19,10 @@ module ZohoHub
19
19
  def put(path, params = {})
20
20
  ZohoHub.connection.put(path, params.to_json)
21
21
  end
22
+
23
+ def delete(path, params = {})
24
+ ZohoHub.connection.delete(path, params.to_json)
25
+ end
22
26
  end
23
27
 
24
28
  def get(path, params = {})
@@ -32,5 +36,9 @@ module ZohoHub
32
36
  def put(path, params = {})
33
37
  self.class.put(path, params)
34
38
  end
39
+
40
+ def delete(path, params = {})
41
+ self.class.delete(path, params)
42
+ end
35
43
  end
36
44
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zoho_hub/validations/validate_length'
4
+ require 'zoho_hub/validations/validate_picklist'
5
+
6
+ module ZohoHub
7
+ module WithValidations
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def add_validation(field, params = {})
14
+ @validations ||= []
15
+
16
+ options = params.dup
17
+ validate = options.delete(:validate)
18
+
19
+ unless validate
20
+ raise ArgumentError, 'You must provide the validation with the `validate` key!'
21
+ end
22
+
23
+ @validations << { field: field, validate: validate }.merge(options)
24
+ end
25
+
26
+ def validations
27
+ @validations || []
28
+ end
29
+ end
30
+
31
+ def validate!
32
+ @errors = []
33
+
34
+ self.class.validations.each { |validation| validate_field!(validation) }
35
+
36
+ @errors
37
+ end
38
+
39
+ def errors
40
+ @errors
41
+ end
42
+
43
+ def validate_field!(params = {})
44
+ options = params.dup
45
+ validate = options.delete(:validate)
46
+
47
+ validator = Module.const_get("Validations::Validate#{validate.downcase.capitalize}")
48
+ validator.new(self, options[:field]).validate(options)
49
+ end
50
+
51
+ def add_error(field, message)
52
+ @errors << { field: field, message: message }
53
+ end
54
+ end
55
+
56
+ class ValidationError < StandardError
57
+ attr_reader :record
58
+
59
+ def initialize(record)
60
+ @record = record
61
+ errors = @record.errors.join(', ')
62
+
63
+ super(errors)
64
+ end
65
+ end
66
+ end
data/lib/zoho_hub.rb CHANGED
@@ -9,7 +9,8 @@ require 'zoho_hub/connection'
9
9
  require 'zoho_hub/errors'
10
10
  require 'zoho_hub/base_record'
11
11
  require 'zoho_hub/settings/module'
12
- require 'zoho_hub/module_builder'
12
+
13
+ require 'zoho_hub/reflection/module_builder'
13
14
 
14
15
  require 'multi_json'
15
16
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zoho_hub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ricardo Otero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-11 00:00:00.000000000 Z
11
+ date: 2019-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -242,29 +242,31 @@ files:
242
242
  - bin/setup
243
243
  - bin/zoho_hub
244
244
  - cache/.git_keep
245
+ - examples/models/campaign.rb
246
+ - examples/models/potential.rb
247
+ - examples/models/quote.rb
245
248
  - lib/zoho_hub.rb
246
249
  - lib/zoho_hub/auth.rb
247
250
  - lib/zoho_hub/base_record.rb
251
+ - lib/zoho_hub/cli/callback_server.rb
252
+ - lib/zoho_hub/cli/read_modules.rb
248
253
  - lib/zoho_hub/configuration.rb
249
254
  - lib/zoho_hub/connection.rb
250
- - lib/zoho_hub/deprecated_and_only_for_reference_records/account.rb
251
- - lib/zoho_hub/deprecated_and_only_for_reference_records/campaign.rb
252
- - lib/zoho_hub/deprecated_and_only_for_reference_records/contact.rb
253
- - lib/zoho_hub/deprecated_and_only_for_reference_records/funder.rb
254
- - lib/zoho_hub/deprecated_and_only_for_reference_records/potential.rb
255
- - lib/zoho_hub/deprecated_and_only_for_reference_records/product.rb
256
- - lib/zoho_hub/deprecated_and_only_for_reference_records/quote.rb
257
255
  - lib/zoho_hub/errors.rb
258
- - lib/zoho_hub/module_builder.rb
259
256
  - lib/zoho_hub/oauth_callback_server.rb
257
+ - lib/zoho_hub/reflection/module_builder.rb
260
258
  - lib/zoho_hub/response.rb
261
259
  - lib/zoho_hub/settings/field.rb
262
260
  - lib/zoho_hub/settings/module.rb
263
261
  - lib/zoho_hub/string_utils.rb
262
+ - lib/zoho_hub/validations/base_validation.rb
263
+ - lib/zoho_hub/validations/validate_length.rb
264
+ - lib/zoho_hub/validations/validate_picklist.rb
264
265
  - lib/zoho_hub/version.rb
265
266
  - lib/zoho_hub/views/variables.erb
266
267
  - lib/zoho_hub/with_attributes.rb
267
268
  - lib/zoho_hub/with_connection.rb
269
+ - lib/zoho_hub/with_validations.rb
268
270
  - zoho_hub.gemspec
269
271
  homepage: https://github.com/rikas/zoho_hub
270
272
  licenses:
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'zoho_hub/records/base_record'
4
-
5
- module ZohoHub
6
- class Account < BaseRecord
7
- attributes :id, :name, :territories, :company_number, :employee_count, :company_type, :industry
8
- attributes :billing_city, :billing_code, :billing_country, :billing_street, :billing_state
9
- attributes :account_type
10
-
11
- # This is the ID to be used when the borrower has no organisation (unlikely) or belongs to
12
- # multiple organisations.
13
- CATCH_ALL_ID = '78265000000826001'
14
-
15
- DEFAULTS = {
16
- account_type: 'Prospect'
17
- }.freeze
18
-
19
- # The translation from attribute name to the JSON field on Zoho. The default behaviour will be
20
- # to Camel_Case the attribute so on this list we should only have exceptions to this rule.
21
- attribute_translation(
22
- id: :id,
23
- name: :Account_Name,
24
- company_number: :company_reg_id,
25
- employee_count: :No_of_Employees,
26
- industry: :Industry_Category
27
- )
28
-
29
- def initialize(params)
30
- attributes.each do |attr|
31
- zoho_key = attr_to_zoho_key(attr)
32
-
33
- send("#{attr}=", params[zoho_key] || params[attr] || DEFAULTS[attr])
34
- end
35
- end
36
-
37
- def to_params
38
- params = super
39
-
40
- params
41
- end
42
- end
43
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'zoho_hub/records/base_record'
4
-
5
- module ZohoHub
6
- class Campaign < BaseRecord
7
- attributes :id, :name
8
-
9
- def initialize(params)
10
- @id = params[:id]
11
- @name = params[:Campaign_Name]
12
- end
13
- end
14
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'zoho_hub/records/base_record'
4
-
5
- module ZohoHub
6
- class Contact < BaseRecord
7
- attributes :id, :email, :salutation, :first_name, :mobile, :role, :last_name
8
- attributes :account_id, :owner_id, :campaign_id, :status, :campaign_detail
9
-
10
- attribute_translation(
11
- id: :id,
12
- role: :platform_cont_type,
13
- status: :platform_cont_status,
14
- use_proceeds: :use_proceeds
15
- )
16
-
17
- DEFAULTS = {
18
- status: 'active',
19
- campaign_detail: 'Web Sign Up'
20
- }.freeze
21
-
22
- def initialize(params)
23
- attributes.each do |attr|
24
- zoho_key = attr_to_zoho_key(attr)
25
-
26
- send("#{attr}=", params[zoho_key] || params[attr] || DEFAULTS[attr])
27
- end
28
-
29
- # Setup values as they come from the Zoho API if needed
30
- @account_id ||= params.dig(:Account_Name, :id)
31
- @owner_id ||= params.dig(:Owner, :id)
32
- @campaign_id ||= params.dig(:Campaign_Lookup, :id)
33
- end
34
-
35
- def to_params
36
- params = super
37
-
38
- params[:Account_Name] = { id: @account_id } if @account_id
39
- params[:Owner] = { id: @owner_id } if @owner_id
40
- params[:Campaign_Lookup] = { id: @campaign_id } if @campaign_id
41
-
42
- params
43
- end
44
- end
45
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ZohoHub
4
- class Vendor < BaseRecord
5
- def initialize(params)
6
- puts Rainbow(params).red.bright
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ZohoHub
4
- class Product < BaseRecord
5
- def initialize(params)
6
- puts Rainbow(params).red.bright
7
- end
8
- end
9
- end