module Automodel::Helpers
Houses some helper methods used directly by {::automodel}.
Public Class Methods
map_tables(connection_handler, subschema: '')
click to toggle source
Takes a connection handler (an object that implements ActiveRecord::ConnectionHandling), scrapes the target database, and returns a list of the tables' metadata.
@param connection_handler [ActiveRecord::ConnectionHandling]
The connection pool/handler to inspect and map out.
@param subschema [String]
The name of an additional namespace with which tables in the target database are prefixed, as eplained in {::automodel}.
@return [Array<Hash>]
An Array where each value is a Hash representing a table in the target database. Each such Hash will define the following keys: - `:name` (String) -- The table name, prefixed with the subschema name (if one is given). - `:columns` (Array<ActiveRecord::ConnectionAdapters::Column>) - `:primary_key` (String, Array<String>) - `:foreign_keys` (Array<ActiveRecord::ConnectionAdapters::ForeignKeyDefinition>) - `:base_name` (String) -- The table name, with no subschema. - `:model_name` (String) -- A Railsy class name for the corresponding model. - `:composite_primary_key` (true, false) - `:column_aliases` (Hash<String, ActiveRecord::ConnectionAdapters::Column>)
# File lib/automodel/helpers.rb, line 34 def map_tables(connection_handler, subschema: '') ## Normalize the "subschema" name. ## subschema = "#{subschema}.".sub(%r{\.+$}, '.').sub(%r{^\.}, '') ## Prep the Automodel::SchemaInspector we'll be using. ## schema_inspector = Automodel::SchemaInspector.new(connection_handler) ## Get as much metadata as possible out of the Automodel::SchemaInspector. ## schema_inspector.tables.map do |table_name| table = {} table[:name] = "#{subschema}#{table_name}" table[:columns] = schema_inspector.columns(table[:name]) table[:primary_key] = schema_inspector.primary_key(table[:name]) table[:foreign_keys] = schema_inspector.foreign_keys(table[:name]) table[:base_name] = table[:name].split('.').last table[:model_name] = table[:base_name].underscore.classify table[:composite_primary_key] = table[:primary_key].is_a? Array table[:column_aliases] = table[:columns].map { |column| [column.name, column] }.to_h table end end
railsy_column_name(column)
click to toggle source
Returns a Railsy name for the given column.
@param column [ActiveRecord::ConnectionAdapters::Column]
The column for which we want to generate a Railsy name.
@return [String]
The given column's name, in Railsy form. Note Date/Datetime columns are not suffixed with "_on" or "_at" per Rails norm, as this can work against you sometimes ("BirthDate" turns into "birth_on"). A future release will address this by building out a comprehensive list of such names and their correct Railsy representation, but that is not currently the case.
# File lib/automodel/helpers.rb, line 77 def railsy_column_name(column) name = railsy_name(column.name) name = name.sub(%r{^is_}, '') if column.type == :boolean name end
railsy_name(name)
click to toggle source
Returns the given name in Railsy form.
@param name [String, Symbol]
The column name for which we want to generate a Railsy name.
@return [String]
The given name, in Railsy form.
# File lib/automodel/helpers.rb, line 94 def railsy_name(name) name.to_s.gsub(%r{[^a-z0-9]+}i, '_').underscore end
register_class(class_object, as:, within: nil)
click to toggle source
Registers the given class as the given name and within the given namespace (if any).
@param class_object [Class]
The class to register.
@param as [String]
The name with which to register the class. Note this should be a base name (no "::").
@param within [String, Symbol, Module, Class]
The module/class under which the given class should be registered. If the named module or class does not exist, as many nested modules as needed are declared so the class can be registered as requested. e.g. Calling this method with an "as" value of `"Sample"` and a "within" value of `"Many::Levels::Deep"` will: check for module/class "Many" and create one as a Module if it doesn't already exist; then check for a module/class "Many::Levels" and create a "Levels" Module within `Many` if it doesn't already exist; then check for a module/class "Many::Levels::Deep" and create a "Deep" Module within `Many::Levels` if it doesn't already exist; and finally register the given class as "Sample" within `Many::Levels::Deep`.
@return [Class]
The newly-registered class (the same value as the originally-submitted "class_object").
# File lib/automodel/helpers.rb, line 124 def register_class(class_object, as:, within: nil) components = within.to_s.split('::').compact.map(&:to_sym) components.unshift(:Kernel) unless components.first.to_s.safe_constantize.present? namespace = components.shift.to_s.constantize components.each do |component| namespace = if component.in? namespace.constants namespace.const_get(component) else namespace.const_set(component, Module.new) end end namespace.const_set(as, class_object) end