class Bootinq

# Bootinq

## Installation

### Ruby on Rails

1. insert `require "bootinq"` on top of `config/application.rb`;
2. find and replace `Bundler.require(*Rails.groups)` with `Bootinq.require`

### Other frameworks

1. locate `Bundler.require(…)` in your app and insert `require "bootinq"` above it;
2. replace previosly located `Bundler.require(…)` line with the `Bootinq.require(…)`.

@example Grape

# config/application.rb

require 'boot'
require 'bootinq'

# Bundler.require :default, ENV['RACK_ENV']
Bootinq.require :default, ENV['RACK_ENV'], verbose: true

@example config/bootinq.yml

env_key: BOOTINQ
default: a

parts:
  s: :shared

mount:
  a: :api
  f: :engine

deps:
  shared:
    in: af

Constants

ALL
DEFAULT
FilterNegValue
VERSION

Attributes

components[R]

@!attribute components [r]

@return [Array<String>]
flags[R]

@!attribute flags [r]

@return [Array<String>]

Public Class Methods

deserialized_config(path: nil) click to toggle source

Reads config @param path [String]

path to yaml config (default: ENV['BOOTINQ_PATH'])

@return [Hash]

deserializes yaml config
# File lib/bootinq.rb, line 131
def self.deserialized_config(path: nil)
  bootinq_yaml = File.read(path || ENV.fetch('BOOTINQ_PATH'))
  psych_safe_load(bootinq_yaml, [Symbol])
end
init(verbose: false, on_ready: nil, &block) click to toggle source

Sets ‘BOOTINQ_PATH` enviroment variable if it is missing & initializes itself @overload init(verbose: false, on_ready:) @overload init(verbose: false, &on_ready) @param verbose [Boolean]

track inquired components

@param on_ready [Proc]

optional ready callback proc

@return [instance]

# File lib/bootinq.rb, line 114
def self.init(verbose: false, on_ready: nil, &block)
  ENV['BOOTINQ_PATH'] ||= File.expand_path('../bootinq.yml', caller_locations(2, 1)[0].path)

  instance
  on_ready = block.to_proc if on_ready.nil? && block_given?
  instance.instance_variable_set(:@_on_ready, on_ready.to_proc) if on_ready

  puts "Bootinq: loading components #{instance.components.join(', ')}" if verbose

  instance.ready!
end
new() click to toggle source

@return [self]

# File lib/bootinq.rb, line 160
def initialize
  config = self.class.deserialized_config
  config.merge!(DEFAULT) { |_, l, r| l.nil? ? r : l }

  @_orig_value = ENV.fetch(config['env_key']) { config['default'] }
  @_neg, @_value = FilterNegValue[@_orig_value, config]

  @_deps = config['deps']

  @flags      = []
  @components = []

  config['parts'].each { |flag, name| enable_component(name, flag: flag.to_s) }
  config['mount'].each { |flag, name| enable_component(name, flag: flag.to_s, as: Mountable) }
end
require(*groups, **options, &on_ready) click to toggle source

Invokes the {init} method with the given options and block, then calls {Bundler.require} with the enabled groups. @see init @see Bundler.require @param groups [Array<Symbol>] @param options [Hash]

initialization options

@option options [Boolean] verbose

track inquired components

@option options [Proc] on_ready

optional ready callback proc

@return [void]

# File lib/bootinq.rb, line 83
def self.require(*groups, **options, &on_ready)
  init(**options, &on_ready)
  Bundler.require(*instance.groups(*groups))
end
setup(*groups, **options) { |instance| ... } click to toggle source

Invokes the {init} method with the given options and block, then calls {Bundler.require} with the enabled groups. @see init @see Bundler.setup @param groups [Array<Symbol>] @param options [Hash]

initialization options

@option options [Boolean] verbose

track inquired components

@option options [Proc] on_ready

optional ready callback proc

@yield [instance] @return [void]

# File lib/bootinq.rb, line 101
def self.setup(*groups, **options, &on_ready) # :yields: Bootinq.instance
  init(**options, &on_ready)
  Bundler.setup(*instance.groups(*groups))
end

Private Class Methods

psych_safe_load(path, permitted_classes) click to toggle source
# File lib/bootinq.rb, line 138
def self.psych_safe_load(path, permitted_classes)
  YAML.safe_load(path, permitted_classes: permitted_classes)
end

Public Instance Methods

[](name)
Alias for: component
component(name) click to toggle source

@param name [String, Symbol] @return [Bootinq::Component]

# File lib/bootinq.rb, line 224
def component(name)
  @components[@components.index(name)]
end
Also aliased as: []
disabled?(name) click to toggle source

Checks if a component with the given name (i.e. the same gem group) is disabled @return [Boolean]

# File lib/bootinq.rb, line 232
def disabled?(name)
  !@components.include?(name)
end
each_mountable() { |component| ... } click to toggle source

Enumerates enabled mountable components @overload each_mountable() @overload each_mountable(&block)

@yield [component]

@return [Enumerator]

# File lib/bootinq.rb, line 241
def each_mountable
  return enum_for(:each_mountable) unless block_given?

  @components.each do |component|
    yield(component) if component.mountable?
  end
end
enable_component(name, flag:, as: Component) { |name, true| ... } click to toggle source

Enables the given component if it is required by flag or when another enabled component depends it. @param name [String]

of the component

@param flag [String]

the component's assigned char flag

@param as [Class]

the component's constructor class

@yield [name, is_enabled] @return [void]

# File lib/bootinq.rb, line 204
def enable_component(name, flag:, as: Component)
  if is_dependency?(name) || @_value.include?(flag)
    @flags      << flag
    @components << as.new(name)
    yield(name, true) if block_given?
  else
    yield(name, false) if block_given?
  end

  nil
end
enabled?(name) click to toggle source

Checks if a component with the given name (i.e. the same gem group) is enabled @return [Boolean]

# File lib/bootinq.rb, line 218
def enabled?(name)
  ALL.include?(name) || @components.include?(name)
end
freeze() click to toggle source

@api private

Calls superclass method
# File lib/bootinq.rb, line 405
def freeze
  @_value.freeze
  @_neg
  @flags.freeze
  @components.freeze
  super
end
groups(*groups) click to toggle source

Merges groups of enabled components with the given ones. When loaded with Rails, it passes them to {Rails.groups} method, otherwise just returns the merged list to use it with {Bundler.require}. @param groups [Array<String, Symbol>] @return [Array<String, Symbol>] merged groups

# File lib/bootinq.rb, line 254
def groups(*groups)
  @components.each do |component|
    next if groups.include?(component.group)
    groups.unshift(component.group)
  end

  defined?(Rails) ? Rails.groups(*groups) : groups
end
is_dependency?(name) click to toggle source

Checks if the named component is dependent by another enabled one. @param name [String, Symbol] @return [Boolean]

# File lib/bootinq.rb, line 399
def is_dependency?(name)
  @_deps.key?(name.to_s) &&
  @_value.count(@_deps.dig(name.to_s, 'in').to_s) > 0
end
not(name = nil, any: nil, all: nil) { || ... } click to toggle source

@overload not(name)

@yield [void] (if component is disabled)
@param name [Symbol] single component's name

@overload not(any:)

@see not_any
@yield [void] (if _any_ matching component is disabled)
@param any [Array<Symbol>] list of components' names

@overload not(all:)

@see not_all
@yield [void] (if _all_ matching components are disabled)
@param all [Array<Symbol>] list of components' names

@return [Boolean] matching status

@example single

Bootinq.not(:frontend) { puts 'not frontend' }

@example any

Bootinq.not(any: %i[frontend backend]) { puts 'neither frontend nor backend' }

@example all

Bootinq.on(all: %i[frontend backend]) { puts 'both disabled' }
# File lib/bootinq.rb, line 347
def not(name = nil, any: nil, all: nil)
  is_matched =
    name ? disabled?(name) :
    any  ? not_any(*any) :
    all  ? not_all(*all) : false

  yield if is_matched

  is_matched
end
not_all(*parts) { || ... } click to toggle source

@yield [void]

if _all_ matching components are disabled

@param parts [Array<String, Symbol>]

list of components' names

@return [Boolean]

matching status
# File lib/bootinq.rb, line 364
def not_all(*parts) # :yields:
  is_matched = parts.reduce(true) { |m, part| m && disabled?(part) }
  yield if is_matched && block_given?
  is_matched
end
not_any(*parts) { || ... } click to toggle source

@yield [void]

if _any_ matching component is disabled

@param parts [Array<String, Symbol>]

list of components' names

@return [Boolean]

matching status
# File lib/bootinq.rb, line 376
def not_any(*parts) # :yields:
  is_matched = parts.reduce(false) { |m, part| m || disabled?(part) }
  yield if is_matched && block_given?
  is_matched
end
on(name = nil, any: nil, all: nil) { || ... } click to toggle source

@overload on(name)

@yield [void] (if component is enabled)
@param name [Symbol] single component's name

@overload on(any:)

@see on_any
@yield [void] (if _any_ matching component is enabled)
@param any [Array<Symbol>] list of components' names

@overload on(all:)

@see on_all
@yield [void] (if _all_ matching components are enabled)
@param all [Array<Symbol>] list of components' names

@return [Boolean] matching status

@example single

Bootinq.on(:frontend) { puts 'frontend' }

@example any

Bootinq.on(any: %i[frontend backend]) { puts 'frontend or backend' }

@example all

Bootinq.on(all: %i[frontend backend]) { puts 'both' }
# File lib/bootinq.rb, line 285
def on(name = nil, any: nil, all: nil)
  if name && ALL.include?(name)
    yield
    return true
  end

  is_matched =
    name ? enabled?(name) :
    any  ? on_any(*any) :
    all  ? on_all(*all) : false

  yield if is_matched

  is_matched
end
on_all(*parts) { || ... } click to toggle source

@yield [void]

if _all_ matching components are enabled

@param parts [Array<String, Symbol>]

list of components' names

@return [Boolean]

matching status
# File lib/bootinq.rb, line 307
def on_all(*parts) # :yields:
  is_matched = parts.reduce(true) { |m, part| m && enabled?(part) }
  yield if is_matched && block_given?
  is_matched
end
on_any(*parts) { || ... } click to toggle source

@yield [void]

if _any_ matching component is enabled

@param parts [Array<String, Symbol>]

list of components' names

@return [Boolean]

matching status
# File lib/bootinq.rb, line 319
def on_any(*parts) # :yields:
  is_matched = parts.reduce(false) { |m, part| m || enabled?(part) }
  yield if is_matched && block_given?
  is_matched
end
ready!() click to toggle source

Once-only set {Bootinq} to ready state firing the ‘@_on_ready` callback. @return [self] on the first call @return [void] after

# File lib/bootinq.rb, line 184
def ready!
  return if ready?
  @ready = true
  if defined?(@_on_ready)
    Bootinq.class_exec(&@_on_ready)
    remove_instance_variable :@_on_ready
  end
  freeze
end
ready?() click to toggle source

@return [Boolean]

# File lib/bootinq.rb, line 177
def ready?
  !!@ready
end
switch() { |switch| ... } click to toggle source

Collector method. @example

Bootinq.switch do |part|
  part.frontend {  }
  part.backend {  }
end

@yield [switch] @see Bootinq::Switch @return [void]

# File lib/bootinq.rb, line 391
def switch
  yield(Switch.new)
  nil
end