console_kit 0.1.2 → 0.1.4

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: 8c68e98f9ea76d56039a31aee01f4642c23bc89e9b41868f988efff84f891647
4
- data.tar.gz: 87be1db75fcb8d80851409a1903fe136d09e6275e5db9797b74f18df28603c63
3
+ metadata.gz: 634e983d59fba9a10d608945d11f0be809c4b3008612c804489a0ee18fd8bcf0
4
+ data.tar.gz: 646bf39efa3b81058524433d88852906313c20e0b584b1e205386bae45b8e638
5
5
  SHA512:
6
- metadata.gz: f339cda7362c7a913918b992395ebd84ab4db2601a8c4d778302ae2579a1adfffab19d8eb63ca669b1d669ed9c58b589bfbe18c0d4ce758b83667b5935ebf304
7
- data.tar.gz: c171cf918f2ea0ebe30c292f7b09847f3974c2fc39c55e21e36845c0399e04d7bc1b6558a8022bf860a57ae25403148ce62ef58748a7aad527ef55a870e6c5dd
6
+ metadata.gz: 70f8f1282f3e6a63588187a86de442b663f17efd40773f7ad6c2916a21917549917d5fa9fba688774e18608f173e8126cee711cb468faf94efdda1ef7653151d
7
+ data.tar.gz: 436bfcb527f71341dd2f6fe1b865a884b4e4208a4dec75820e2bc46068de85db706f2e037e2b1aa94f07091600e204c35ef89cff612dd2bb103ae6d1baa414f7
data/.reek.yml ADDED
@@ -0,0 +1,4 @@
1
+ detectors:
2
+ UncommunicativeVariableName:
3
+ exclude:
4
+ - e
data/.rubocop.yml CHANGED
@@ -1,5 +1,10 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 3.1
3
+ NewCops: enable
4
+
5
+ plugins:
6
+ - rubocop-rspec
7
+ - rubocop-rake
3
8
 
4
9
  Metrics/BlockLength:
5
10
  Exclude:
data/CHANGELOG.md CHANGED
@@ -6,6 +6,24 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [0.1.4] - 2025-09-30
10
+ ### Added
11
+ - Minor Fixes and Improvements
12
+
13
+ ---
14
+
15
+ ## [0.1.3] - 2025-08-12
16
+ ### Added
17
+ - `ConsoleKit.current_tenant` method to retrieve the current tenant at runtime.
18
+ - `ConsoleKit.reset_current_tenant` to reset tenant selection.
19
+ - `pretty_output` configuration added with ability to manually toggle CLI verbosity.
20
+
21
+ ### Changed
22
+ - Refactored internal logic for improved maintainability and future extensibility.
23
+ - Enhanced test coverage for better reliability and edge case handling.
24
+
25
+ ---
26
+
9
27
  ## [0.1.2] - 2025-07-23
10
28
  ### Added
11
29
  - Changelog added.
@@ -38,6 +56,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
38
56
 
39
57
  ## [Unreleased]
40
58
 
59
+ [0.1.4]: https://github.com/Soumyadeep-ai/console_kit/releases/tag/v0.1.4
60
+ [0.1.3]: https://github.com/Soumyadeep-ai/console_kit/releases/tag/v0.1.3
41
61
  [0.1.2]: https://github.com/Soumyadeep-ai/console_kit/releases/tag/v0.1.2
42
62
  [0.1.1]: https://github.com/Soumyadeep-ai/console_kit/releases/tag/v0.1.1
43
63
  [0.1.0]: https://github.com/Soumyadeep-ai/console_kit/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # ConsoleKit
2
2
 
3
+ ![Gem Version](https://img.shields.io/gem/v/console_kit.svg)
4
+ ![Gem Downloads](https://img.shields.io/gem/dt/console_kit.svg)
5
+ ![Build Status](https://github.com/Soumyadeep-ai/console_kit/actions/workflows/release.yml/badge.svg)
6
+ ![License](https://img.shields.io/github/license/Soumyadeep-ai/console_kit)
7
+ ![Ruby](https://img.shields.io/badge/ruby-%3E=3.1.0-red)
8
+
3
9
  A simple and flexible multi-tenant console setup toolkit for Rails applications.
4
10
 
5
11
  ConsoleKit helps you manage tenant-specific database connections and context configuration via an easy CLI interface and Rails integration.
@@ -52,9 +58,39 @@ ConsoleKit.configure do |config|
52
58
  }
53
59
 
54
60
  config.context_class = CurrentContext
61
+
62
+ # Optional: Toggle pretty CLI output
63
+ config.pretty_output = true
55
64
  end
56
65
  ```
57
66
 
67
+ ## Console Usage
68
+
69
+ When launching the Rails console, ConsoleKit will prompt you to select a tenant (if tenants are configured).
70
+ You can also manually interact with it:
71
+
72
+ ### Get Current Tenant
73
+ ```ruby
74
+ ConsoleKit.current_tenant
75
+ # => :tenant_one
76
+ ```
77
+
78
+ ### Reset Current Tenant
79
+ ```ruby
80
+ ConsoleKit.reset_current_tenant
81
+ # => nil
82
+ ```
83
+
84
+ ### Manually Disable Pretty Output
85
+ ```ruby
86
+ ConsoleKit.enable_pretty_output
87
+ ```
88
+
89
+ ### Manually Disable Pretty Output
90
+ ```ruby
91
+ ConsoleKit.disable_pretty_output
92
+ ```
93
+
58
94
  ## Development
59
95
 
60
96
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -63,7 +99,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
63
99
 
64
100
  ## Contributing
65
101
 
66
- Bug reports and pull requests are welcome on GitHub at https://github.com/Soumyadeep-ai/console_kit. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Soumyadeep-ai/console_kit/blob/main/CODE_OF_CONDUCT.md).
102
+ Bug reports and pull requests are welcome on GitHub at [Console Kit](https://github.com/Soumyadeep-ai/console_kit). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Soumyadeep-ai/console_kit/blob/main/CODE_OF_CONDUCT.md).
67
103
 
68
104
  ## License
69
105
 
data/SECURITY.md ADDED
@@ -0,0 +1,28 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We do **not maintain multiple supported versions**. Only the latest released version is eligible for security updates.
6
+
7
+ Once a new version is released, the previous version is branched and locked, and will no longer receive updates — including security patches.
8
+
9
+ | Version | Supported |
10
+ | ------- | ------------------ |
11
+ | 0.1.4 | :white_check_mark: |
12
+ | 0.1.3 | :x: |
13
+ | 0.1.2 | :x: |
14
+ | 0.1.1 | :x: |
15
+ | 0.1.0 | :x: |
16
+
17
+ ## Reporting a Vulnerability
18
+
19
+ If you discover a security vulnerability, please use the GitHub [Security Advisories](https://github.com/Soumyadeep-ai/console_kit/security/advisories/new) feature to report it privately.
20
+
21
+ We follow this process:
22
+ - All reported vulnerabilities are reviewed promptly.
23
+ - A new version with security fixes will be released.
24
+ - Once validated, we will publish an advisory and issue a patched release if necessary.
25
+
26
+ Please avoid disclosing vulnerabilities publicly until we’ve had a chance to review and respond.
27
+
28
+ For more details, visit [GitHub Docs: Reporting a Vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability).
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConsoleKit
4
+ # Stores ConsoleKit configurations such as tenant map and context behavior
5
+ class Configuration
6
+ attr_reader :pretty_output, :tenants, :context_class
7
+
8
+ def initialize(tenants: nil, context_class: nil)
9
+ @pretty_output = true
10
+ @tenants = tenants
11
+ @context_class = context_class
12
+ end
13
+
14
+ %i[pretty_output tenants context_class].each do |attr|
15
+ define_method("#{attr}=") { |value| instance_variable_set("@#{attr}", value) }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConsoleKit
4
+ module Connections
5
+ # Parent class for connection handlers
6
+ class BaseConnectionHandler
7
+ attr_reader :context
8
+
9
+ def initialize(context) = @context = context
10
+
11
+ def connect
12
+ raise NotImplementedError, "#{self.class} must implement #connect"
13
+ end
14
+
15
+ def available? = false
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'sql_connection_handler'
4
+ require_relative 'mongo_connection_handler'
5
+
6
+ module ConsoleKit
7
+ module Connections
8
+ # Manages available connection handlers
9
+ class ConnectionManager
10
+ class << self
11
+ def available_handlers(context)
12
+ handler_classes.filter_map do |klass|
13
+ handler = klass.new(context)
14
+ handler if handler.available?
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def handler_classes = BaseConnectionHandler.descendants
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require_relative 'base_connection_handler'
5
+
6
+ module ConsoleKit
7
+ module Connections
8
+ # Handles MongoDB connections
9
+ class MongoConnectionHandler < BaseConnectionHandler
10
+ extend Forwardable
11
+
12
+ def_delegator :@context, :tenant_mongo_db
13
+
14
+ def connect
15
+ return if tenant_mongo_db.blank?
16
+
17
+ Output.print_info("Switching to MongoDB client: #{tenant_mongo_db}")
18
+ Mongoid.override_client(tenant_mongo_db)
19
+ rescue NoMethodError
20
+ Output.print_warning('Mongoid.override_client is not defined.')
21
+ end
22
+
23
+ def available? = defined?(Mongoid)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require_relative 'base_connection_handler'
5
+
6
+ module ConsoleKit
7
+ module Connections
8
+ # Handles SQL connections
9
+ class SqlConnectionHandler < BaseConnectionHandler
10
+ extend Forwardable
11
+
12
+ def_delegator :@context, :tenant_shard
13
+
14
+ def connect
15
+ return if tenant_shard.blank?
16
+
17
+ Output.print_info("Establishing SQL connection to shard: #{tenant_shard}")
18
+ ApplicationRecord.establish_connection(tenant_shard.to_sym)
19
+ end
20
+
21
+ def available? = defined?(ApplicationRecord)
22
+ end
23
+ end
24
+ end
@@ -3,40 +3,50 @@
3
3
  module ConsoleKit
4
4
  # Handles Console outputs
5
5
  module Output
6
- class << self
7
- def print_error(text)
8
- print_message("[āœ—] #{text}", '1;31') # Red
9
- end
6
+ PREFIX = '[ConsoleKit]'
7
+ TYPES = {
8
+ error: { symbol: '[āœ—]', color: '1;31' },
9
+ success: { symbol: '[āœ“]', color: '1;32' },
10
+ warning: { symbol: '[!]', color: '1;33' },
11
+ prompt: { symbol: nil, color: '1;36' },
12
+ header: { symbol: nil, color: '1;34' },
13
+ trace: { symbol: nil, color: '0;90' },
14
+ info: { symbol: nil, color: nil }
15
+ }.freeze
10
16
 
11
- def print_success(text)
12
- print_message("[āœ“] #{text}", '1;32') # Green
17
+ class << self
18
+ TYPES.each_key do |type|
19
+ define_method("print_#{type}") do |text, timestamp: false|
20
+ formatted = (type == :header ? "\n=== #{text} ===" : text)
21
+ print_with(type, formatted, timestamp)
22
+ end
13
23
  end
14
24
 
25
+ # Backtrace prints always with timestamp, no param
15
26
  def print_backtrace(exception)
16
- exception.backtrace.each { |line| print_message(" #{line}", '0;90') } # Dim gray
27
+ exception&.backtrace&.each { |line| print_with(:trace, " #{line}", true) }
17
28
  end
18
29
 
19
- def print_header(text)
20
- print_message("\n=== #{text} ===", '1;34') # Bold Blue
21
- end
30
+ private
22
31
 
23
- def print_info(text)
24
- print_message(text)
32
+ def print_with(type, text, timestamp)
33
+ meta = TYPES.fetch(type)
34
+ message = build_message(text, meta[:symbol], timestamp)
35
+ output(message, meta[:color])
25
36
  end
26
37
 
27
- def print_prompt(text)
28
- print_message(text, '1;36') # Cyan
38
+ def build_message(text, symbol, timestamp)
39
+ "#{PREFIX} #{timestamp_prefix(timestamp)}#{symbol_prefix(symbol)}#{text}"
29
40
  end
30
41
 
31
- def print_warning(text)
32
- print_message("[!] #{text}", '1;33') # Yellow
33
- end
42
+ def prefix_for(value) = value ? yield(value) : ''
43
+ def timestamp_prefix(timestamp) = prefix_for(timestamp) { Time.current.strftime('[%Y-%m-%d %H:%M:%S] ') }
44
+ def symbol_prefix(symbol) = prefix_for(symbol) { |sym| "#{sym} " }
34
45
 
35
- private
46
+ def output(message, color)
47
+ return puts message unless ConsoleKit.configuration.pretty_output && color
36
48
 
37
- def print_message(text, color = nil)
38
- msg = "[ConsoleKit] #{text}"
39
- puts color ? "\e[#{color}m#{msg}\e[0m" : msg
49
+ puts "\e[#{color}m#{message}\e[0m"
40
50
  end
41
51
  end
42
52
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConsoleKit
4
- # Railtie
4
+ # Railtie for integrating ConsoleKit with Rails console.
5
5
  class Railtie < Rails::Railtie
6
- console do
7
- ConsoleKit.setup
8
- end
6
+ console { ConsoleKit::Setup.setup }
9
7
  end
10
8
  end
@@ -6,46 +6,64 @@ require_relative 'output'
6
6
 
7
7
  # Core Logic for initial Setup
8
8
  module ConsoleKit
9
- class << self
10
- attr_accessor :tenants, :context_class
9
+ # Does the initial setup
10
+ module Setup
11
+ class << self
12
+ attr_reader :current_tenant
11
13
 
12
- def setup
13
- return Output.print_error('No tenants configured.') if tenants.nil? || tenants.empty?
14
+ def setup = run_setup
15
+ def tenant_setup_successful? = !@current_tenant.to_s.empty?
14
16
 
15
- tenant_key = resolve_tenant_key
16
- return Output.print_error('No tenant selected. Loading without tenant configuration.') unless tenant_key
17
+ def reset_current_tenant
18
+ return warn_no_tenants unless tenants?
17
19
 
18
- initialize_tenant(tenant_key)
19
- rescue StandardError => e
20
- handle_setup_error(e)
21
- end
20
+ warn_reset if @current_tenant
21
+ TenantConfigurator.clear if @current_tenant
22
22
 
23
- def configure
24
- yield self
25
- end
23
+ @current_tenant = nil
24
+ setup
25
+ end
26
26
 
27
- private
27
+ private
28
28
 
29
- def resolve_tenant_key
30
- single_tenant? || non_interactive? ? tenants.keys.first : TenantSelector.select(tenants, tenants.keys)
31
- end
29
+ def run_setup
30
+ return Output.print_error('No tenants configured.') if no_tenants?
32
31
 
33
- def single_tenant?
34
- tenants.size == 1
35
- end
32
+ select_and_configure
33
+ rescue StandardError => e
34
+ handle_error(e)
35
+ end
36
36
 
37
- def non_interactive?
38
- !$stdin.tty?
39
- end
37
+ def select_and_configure
38
+ key = select_tenant_key
39
+ return Output.print_error('No tenant selected. Loading without tenant configuration.') unless key
40
40
 
41
- def initialize_tenant(tenant_key)
42
- TenantConfigurator.configure_tenant(tenant_key, tenants, context_class)
43
- Output.print_success("Tenant initialized: #{tenant_key}")
44
- end
41
+ configure(key)
42
+ end
43
+
44
+ def configure(key)
45
+ TenantConfigurator.configure_tenant(key)
46
+ return unless TenantConfigurator.configuration_success
47
+
48
+ @current_tenant = key
49
+ Output.print_success("Tenant initialized: #{key}")
50
+ end
51
+
52
+ def tenants = ConsoleKit.configuration.tenants
53
+ def context_class = ConsoleKit.configuration.context_class
54
+ def tenants? = tenants&.any?
55
+ def no_tenants? = !tenants?
56
+ def select_tenant_key = auto_select? ? tenants.keys.first : TenantSelector.select
57
+ def auto_select? = single_tenant? || non_interactive?
58
+ def single_tenant? = tenants.size == 1
59
+ def non_interactive? = !$stdin.tty?
60
+ def warn_no_tenants = Output.print_warning('Cannot reset tenant: No tenants configured.')
61
+ def warn_reset = Output.print_warning("Resetting tenant: #{@current_tenant}")
45
62
 
46
- def handle_setup_error(error)
47
- Output.print_error("Error setting up tenant: #{error.message}")
48
- Output.print_backtrace(error)
63
+ def handle_error(error)
64
+ Output.print_error("Error setting up tenant: #{error.message}")
65
+ Output.print_backtrace(error)
66
+ end
49
67
  end
50
68
  end
51
69
  end
@@ -1,36 +1,71 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'output'
4
+ require_relative 'connections/connection_manager'
4
5
 
5
6
  module ConsoleKit
6
7
  # For tenant configuration
7
8
  module TenantConfigurator
8
9
  class << self
9
- def configure_tenant(key, tenants, context_class)
10
- config = tenants[key]
11
- return Output.print_error("No configuration found for tenant: #{key}") unless config
10
+ attr_reader :configuration_success
12
11
 
13
- constants = config[:constants]
14
- apply_context(context_class, constants)
15
- setup_database_connections(context_class)
12
+ def configure_tenant(key)
13
+ constants = ConsoleKit.configuration.tenants[key]&.[](:constants)
14
+ return missing_config_error(key) unless constants
16
15
 
17
- Output.print_success("Tenant set to: #{key}")
16
+ perform_configuration(key, constants)
18
17
  rescue StandardError => e
19
- Output.print_error("Failed to configure tenant '#{key}': #{e.message}")
20
- Output.print_backtrace(e)
18
+ handle_error(e, key)
19
+ end
20
+
21
+ def clear
22
+ @configuration_success = false
23
+ %i[tenant_shard tenant_mongo_db partner_identifier].each do |attr|
24
+ ConsoleKit.configuration.context_class.public_send("#{attr}=", nil)
25
+ end
26
+ Output.print_info('Tenant context has been cleared.')
21
27
  end
22
28
 
23
29
  private
24
30
 
25
- def apply_context(context_class, constants)
26
- context_class.tenant_shard = constants[:shard]
27
- context_class.tenant_mongo_db = constants[:mongo_db]
28
- context_class.partner_identifier = constants[:partner_code]
31
+ def validate_constants!(constants)
32
+ missing = %i[shard partner_code] - constants.keys
33
+ raise "Tenant constants missing keys: #{missing.join(', ')}" unless missing.empty?
34
+ end
35
+
36
+ def missing_config_error(key)
37
+ @configuration_success = false
38
+ Output.print_error("No configuration found for tenant: #{key}")
39
+ end
40
+
41
+ def perform_configuration(key, constants)
42
+ validate_constants!(constants)
43
+ apply_context(constants)
44
+ configure_success(key)
45
+ end
46
+
47
+ def apply_context(constant)
48
+ ctx = ConsoleKit.configuration.context_class
49
+ ctx.tenant_shard = constant[:shard]
50
+ ctx.tenant_mongo_db = constant[:mongo_db]
51
+ ctx.partner_identifier = constant[:partner_code]
52
+
53
+ setup_connections(ctx)
54
+ end
55
+
56
+ def setup_connections(context)
57
+ ConsoleKit::Connections::ConnectionManager.available_handlers(context).each(&:connect)
58
+ end
59
+
60
+ def configure_success(key)
61
+ Output.print_success("Tenant set to: #{key}")
62
+ @configuration_success = true
29
63
  end
30
64
 
31
- def setup_database_connections(context_class)
32
- ApplicationRecord.establish_connection(context_class.tenant_shard.to_sym)
33
- Mongoid.override_client(context_class.tenant_mongo_db.to_s)
65
+ def handle_error(error, key)
66
+ @configuration_success = false
67
+ Output.print_error("Failed to configure tenant '#{key}': #{error.message}")
68
+ Output.print_backtrace(error)
34
69
  end
35
70
  end
36
71
  end
@@ -5,57 +5,64 @@ require_relative 'output'
5
5
  module ConsoleKit
6
6
  # For tenant selection
7
7
  module TenantSelector
8
- class << self
9
- def select(tenants, keys)
10
- print_tenant_selection_menu(tenants, keys)
11
-
12
- max_attempts = 3
13
- max_attempts.times do
14
- index = prompt_user_for_selection(keys.size)
15
- return nil if index.zero?
16
- return keys[index - 1] if index.positive?
17
- end
8
+ RETRY_LIMIT = 3
9
+ DEFAULT_SELECTION = '1'
18
10
 
19
- nil
11
+ class << self
12
+ def select
13
+ attempt_selection(RETRY_LIMIT)
20
14
  end
21
15
 
22
16
  private
23
17
 
24
- def print_tenant_selection_menu(tenants, keys)
18
+ def attempt_selection(retries_left)
19
+ return nil if retries_left.zero?
20
+
21
+ print_tenant_selection_menu
22
+ selection = parse_user_selection
23
+ selection ? resolve_selection(selection) : attempt_selection(retries_left - 1)
24
+ end
25
+
26
+ def print_tenant_selection_menu
25
27
  Output.print_header('Multiple tenants detected. Please choose one:')
26
28
  Output.print_info(' 0. Load without tenant (no tenant configuration)')
27
29
 
28
- keys.each_with_index do |key, index|
29
- partner = tenants.dig(key, :constants, :partner_code) || 'N/A'
30
- Output.print_info(" #{index + 1}. #{key} (partner: #{partner})")
30
+ ConsoleKit.tenants.keys.each_with_index do |key, index|
31
+ Output.print_info(" #{index + 1}. #{key} (partner: #{tenant_partner(key)})")
31
32
  end
32
33
  end
33
34
 
34
- def prompt_user_for_selection(max_index)
35
- Output.print_prompt("\nEnter the number of the tenant you want (or press Enter for default '1'): ")
36
- input = $stdin.gets&.chomp&.strip
37
- input = '1' if input.to_s.empty?
35
+ def tenant_partner(key) = ConsoleKit.tenants.dig(key, :constants, :partner_code) || 'N/A'
38
36
 
39
- return invalid_input_response unless valid_integer?(input)
37
+ def parse_user_selection
38
+ input = read_input_with_default
39
+ return handle_invalid_input('Invalid input. Please enter a number.') unless valid_integer?(input)
40
40
 
41
- parsed_index = input.to_i
42
- return invalid_range_response(max_index) unless parsed_index.between?(0, max_index)
41
+ index = input.to_i
42
+ unless valid_selection_index?(index)
43
+ return handle_invalid_input("Selection must be between 0 and #{max_index}.")
44
+ end
43
45
 
44
- parsed_index
46
+ index
45
47
  end
46
48
 
47
- def valid_integer?(input)
48
- input.match?(/\A\d+\z/)
49
+ def read_input_with_default
50
+ prompt_message = "\nEnter the number of the tenant you want " \
51
+ "(or press Enter for default '#{DEFAULT_SELECTION}'): "
52
+ Output.print_prompt(prompt_message)
53
+ input = $stdin.gets&.chomp&.strip
54
+ input.to_s.empty? ? DEFAULT_SELECTION : input
49
55
  end
50
56
 
51
- def invalid_input_response
52
- Output.print_warning('Invalid input. Please enter a number.')
53
- -1
54
- end
57
+ def handle_invalid_input(message) = Output.print_warning(message).then { nil }
58
+ def valid_integer?(input) = input.match?(/\A\d+\z/)
59
+ def max_index = ConsoleKit.tenants.size
60
+ def valid_selection_index?(index) = index.between?(0, max_index)
61
+
62
+ def resolve_selection(index)
63
+ return nil if index.zero?
55
64
 
56
- def invalid_range_response(max_index)
57
- Output.print_warning("Selection must be between 0 and #{max_index}.")
58
- -1
65
+ ConsoleKit.tenants.keys[index - 1]
59
66
  end
60
67
  end
61
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConsoleKit
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
data/lib/console_kit.rb CHANGED
@@ -1,10 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'console_kit/version'
4
+ require_relative 'console_kit/configuration'
4
5
  require_relative 'console_kit/setup'
5
6
  require_relative 'console_kit/railtie' if defined?(Rails::Railtie)
6
7
 
8
+ # Main module for console kit
7
9
  module ConsoleKit
10
+ # Base error class for ConsoleKit-related exceptions.
8
11
  class Error < StandardError; end
9
- # Your code goes here...
12
+
13
+ class << self
14
+ def configure = yield(configuration)
15
+
16
+ def configuration = Thread.current[:console_kit_configuration] ||= Configuration.new
17
+ def reset_configuration! = Thread.current[:console_kit_configuration] = nil
18
+
19
+ %i[pretty_output tenants context_class].each do |name|
20
+ define_method(name) { configuration.public_send(name) }
21
+ define_method("#{name}=") { |val| configuration.public_send("#{name}=", val) }
22
+ end
23
+
24
+ def current_tenant = Setup.current_tenant
25
+ def reset_current_tenant = Setup.reset_current_tenant
26
+
27
+ def enable_pretty_output = configuration.pretty_output = true
28
+ def disable_pretty_output = configuration.pretty_output = false
29
+ end
10
30
  end
@@ -9,20 +9,26 @@ module ConsoleKit
9
9
  class InstallGenerator < Rails::Generators::Base
10
10
  source_root File.expand_path('templates', __dir__)
11
11
 
12
+ class_option :force, type: :boolean, default: false, desc: 'Overwrite existing files'
13
+
12
14
  def copy_initializer
15
+ force = options[:force]
13
16
  initializer_path = Rails.root.join('config', 'initializers', 'console_kit.rb')
14
17
 
15
- if File.exist?(initializer_path)
16
- say_status('skipped', "Initializer already exists: #{initializer_path}", :yellow)
18
+ if File.exist?(initializer_path) && !force
19
+ say_status :skipped, "Initializer already exists: #{initializer_path}", :yellow
17
20
  else
18
- template 'console_kit.rb', 'config/initializers/console_kit.rb'
19
- say_status('created', "Initializer generated at #{initializer_path}", :green)
21
+ template 'console_kit.rb', 'config/initializers/console_kit.rb', force: force
22
+ say_status :created, "Initializer generated at #{initializer_path}", :green
20
23
  end
21
24
  end
22
25
 
23
26
  def remind_about_customization
24
27
  say "\nāœ… Setup complete!", :green
25
- say 'šŸ‘‰ Please update `config/initializers/console_kit.rb` to set your `tenants` and `context_class`.', :green
28
+ say 'šŸ“„ Modify `config/initializers/console_kit.rb`:', :green
29
+ %w[tenants context_class].each do |field|
30
+ say " - Set `#{field}` (required)", :green
31
+ end
26
32
  end
27
33
  end
28
34
  end
@@ -5,15 +5,20 @@
5
5
 
6
6
  Rails.application.config.after_initialize do
7
7
  ConsoleKit.configure do |config|
8
- # TODO: Set your tenants source in the following format
8
+ # TODO: Set your tenants source, example:
9
9
  # {
10
- # key:
11
- # {
12
- # constants:
13
- # {
14
- # shard: # Active Record Shard
15
- # mongo_db: # Mongo Shard (If Mongo Is being used)
16
- # partner_code: # If partners are needed
10
+ # tenant_a: {
11
+ # constants: {
12
+ # shard: :shard_1,
13
+ # mongo_db: 'mongo_db_1',
14
+ # partner_code: 'partner_a'
15
+ # }
16
+ # },
17
+ # tenant_b: {
18
+ # constants: {
19
+ # shard: :shard_2,
20
+ # mongo_db: 'mongo_db_2',
21
+ # partner_code: 'partner_b'
17
22
  # }
18
23
  # }
19
24
  # }
@@ -21,5 +26,18 @@ Rails.application.config.after_initialize do
21
26
 
22
27
  # TODO: Set your context class (e.g., CurrentContext)
23
28
  config.context_class = nil
29
+
30
+ # Toggle pretty output on/off (default: true)
31
+ config.pretty_output = true
32
+
33
+ if config.tenants.nil?
34
+ warn '[ConsoleKit] Warning: `tenants` is not configured. ' \
35
+ 'Please set it in config/initializers/console_kit.rb'
36
+ end
37
+
38
+ if config.context_class.nil?
39
+ warn '[ConsoleKit] Warning: `context_class` is not configured. ' \
40
+ 'Please set it in config/initializers/console_kit.rb'
41
+ end
24
42
  end
25
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: console_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soumyadeep Pal
@@ -44,6 +44,7 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - ".reek.yml"
47
48
  - ".rspec"
48
49
  - ".rubocop.yml"
49
50
  - CHANGELOG.md
@@ -51,7 +52,13 @@ files:
51
52
  - LICENSE.txt
52
53
  - README.md
53
54
  - Rakefile
55
+ - SECURITY.md
54
56
  - lib/console_kit.rb
57
+ - lib/console_kit/configuration.rb
58
+ - lib/console_kit/connections/base_connection_handler.rb
59
+ - lib/console_kit/connections/connection_manager.rb
60
+ - lib/console_kit/connections/mongo_connection_handler.rb
61
+ - lib/console_kit/connections/sql_connection_handler.rb
55
62
  - lib/console_kit/output.rb
56
63
  - lib/console_kit/railtie.rb
57
64
  - lib/console_kit/setup.rb
@@ -69,6 +76,7 @@ metadata:
69
76
  homepage_uri: https://github.com/Soumyadeep-ai/console_kit
70
77
  source_code_uri: https://github.com/Soumyadeep-ai/console_kit
71
78
  changelog_uri: https://github.com/Soumyadeep-ai/console_kit/blob/main/CHANGELOG.md
79
+ rubygems_mfa_required: 'true'
72
80
  rdoc_options: []
73
81
  require_paths:
74
82
  - lib