lib/rflow/configuration.rb in rflow-1.3.0 vs lib/rflow/configuration.rb in rflow-1.3.1

- old
+ new

@@ -1,43 +1,46 @@ class RFlow # Contains all the configuration data and methods for RFlow. - # Interacts directly with underlying sqlite database, and keeps a + # Interacts directly with underlying SQLite database, and keeps a # registry of available data types, extensions, and components. # Also includes an external DSL, RubyDSL, that can be used in # crafting config-like files that load the database. # - # Configuration provides a MVC-like framework for config files, - # where the models are the Setting, Component, Port, and Connection + # {Configuration} provides a MVC-like framework for config files, + # where the models are the {Setting}, {Component}, {Port}, and {Connection} # subclasses, the controllers are things like RubyDSL, and the views - # are defined relative to the controllers + # are defined relative to the controllers. class Configuration # A collection class for data extensions that supports a naive # prefix-based 'inheritance' on lookup. When looking up a key - # with [] all existing keys will be examined to determine if the + # with {[]} all existing keys will be examined to determine if the # existing key is a string prefix of the lookup key. All the # results are consolidated into a single, flattened array. class DataExtensionCollection def initialize # TODO: choose a different data structure ... @extensions_for = Hash.new {|hash, key| hash[key] = []} end # Return an array of all of the values that have keys that are # prefixes of the lookup key. + # @return [Array] def [](key) @extensions_for. find_all {|data_type, _| key.to_s.start_with?(data_type) }. flat_map {|_, extensions| extensions } end # Adds a data extension for a given data type to the collection + # @return [void] def add(data_type, extension) @extensions_for[data_type.to_s] << extension end # Remove all elements from the collection. Useful for testing, # not much else + # @return [void] def clear @extensions_for.clear end end @@ -47,92 +50,101 @@ end class << self # A collection of data types (schemas) indexed by their name and # their schema type ('avro'). + # @return [Hash] def available_data_types @available_data_types ||= Hash.new {|hash, key| hash[key] = {}} end - # A DataExtensionCollection to hold available extensions that - # will be applied to the de-serialized data types + # A {DataExtensionCollection} to hold available extensions that + # will be applied to the de-serialized data types. + # @return [DataExtensionCollection] def available_data_extensions @available_data_extensions ||= DataExtensionCollection.new end # A Hash of defined components, usually automatically populated - # when a component subclasses RFlow::Component + # when a component subclasses {RFlow::Component}. + # @return [Hash] def available_components @available_components ||= {} end - # TODO: refactor each of these add_available_* into collections to - # make DRYer. Also figure out what to do with all to to_syms - - # Add a schema to the available_data_types class attribute. - # Schema is indexed by data_type_name and schema/serialization - # type. 'avro' is currently the only supported serialization_type. + # Add a schema to the {available_data_types} class attribute. + # Schema is indexed by +name+ and +serialization_type+. + # +avro+ is currently the only supported +serialization_type+. + # @return [void] def add_available_data_type(name, serialization_type, schema) + # TODO: refactor each of these add_available_* into collections to + # make DRYer. Also figure out what to do with all to to_syms raise ArgumentError, "Data serialization_type must be 'avro' for '#{name}'" unless serialization_type == 'avro' if available_data_types[name.to_s].include? serialization_type.to_s raise ArgumentError, "Data type '#{name}' already defined for serialization_type '#{serialization_type}'" end available_data_types[name.to_s][serialization_type.to_s] = schema end - # Add a data extension to the available_data_extensions class - # attributes. The data_extension parameter should be the name of - # a ruby module that will extend RFlow::Message::Data object to - # provide additional methods/capability. Naive, prefix-based - # inheritance is possible, see available_data_extensions or the - # DataExtensionCollection class + # Add a data extension to the {available_data_extensions} class + # attribute. The +extension+ parameter should be the name of + # a ruby module that will extend {RFlow::Message::Data} to + # provide additional methods/capability. Naive, prefix-based + # inheritance is possible, see {available_data_extensions} or + # {DataExtensionCollection}. + # @return [void] def add_available_data_extension(data_type_name, extension) unless extension.is_a? Module raise ArgumentError, "Invalid data extension #{extension} for #{data_type_name}. Only Ruby Modules allowed" end available_data_extensions.add data_type_name, extension end - # Used when RFlow::Component is subclassed to add another + # Used when {RFlow::Component} is subclassed to add another # available component to the list. + # @return [void] def add_available_component(component) if available_components.include?(component.name) raise ArgumentError, "Component already '#{component.name}' already defined" end available_components[component.name] = component end - # Connect to the configuration sqlite database, but use the - # ConfigurationItem class to protect the connection information from - # other ActiveRecord apps (i.e. Rails) + # Connect to the configuration SQLite database, but use + # {ConfigurationItem} to protect the connection information from + # other ActiveRecord apps (i.e. Rails). + # @return [void] def establish_config_database_connection(database_path) RFlow.logger.debug "Establishing connection to config database (#{Dir.getwd}) '#{database_path}'" ActiveRecord::Base.logger = RFlow.logger ConfigurationItem.establish_connection(:adapter => 'sqlite3', :database => database_path) end # Using default ActiveRecord migrations, attempt to migrate the # database to the latest version. + # @return [void] def migrate_database RFlow.logger.debug 'Applying default migrations to config database' migrations_path = File.join(File.dirname(__FILE__), 'configuration', 'migrations') ActiveRecord::Migration.verbose = false ActiveRecord::Migrator.migrate migrations_path end # Load the config file, which should load/process/store all the - # elements. Only run this after the database has been setup + # elements. Only run this after the database has been setup + # @return [void] def process_config_file(path) RFlow.logger.info "Processing config file (#{Dir.getwd}) '#{path}'" load path end # Connect to the configuration database, migrate it to the latest # version, and process a config file if provided. + # @return [void] def initialize_database(database_path, config_file_path = nil) RFlow.logger.debug "Initializing config database (#{Dir.getwd}) '#{database_path}'" # TODO should not need this line ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => database_path) @@ -154,10 +166,11 @@ self.new(database_path) end # Make sure that the configuration has all the necessary values set. + # @return [void] def merge_defaults! Setting::DEFAULTS.each do |name, default_value_or_proc| value = default_value_or_proc.is_a?(Proc) ? default_value_or_proc.call() : default_value_or_proc setting = Setting.find_or_create_by(:name => name, :value => value) unless setting.valid? @@ -182,10 +195,12 @@ rescue ActiveRecord::StatementInvalid => e raise ArgumentError, "Invalid schema in configuration database: #{e.message}" end end + # Output the RFlow configuration to a pretty-printed String. + # @return [String] def to_s string = "Configuration:\n" settings.each do |setting| string << "Setting: '#{setting.name}' = '#{setting.value}'\n" @@ -206,16 +221,39 @@ end end string end + # Retrieve a setting value by name from the SQLite database. + # @return [Object] def [](name); Setting.find_by_name(name).value rescue nil; end + + # Retrieve all the {Setting}s from the SQLite database. + # @return [Array<Setting>] def settings; Setting.all; end + + # Retrieve all the {Shard}s from the SQLite database. + # @return [Array<Shard>] def shards; Shard.all; end + + # Retrieve all the {Connection}s from the SQLite database. + # @return [Array<Connection>] def connections; Connection.all; end + + # Retrieve a single {Shard} by UUID from the SQLite database. + # @return [Shard] def shard(uuid); Shard.find_by_uuid uuid; end + + # Retrieve all the {Component}s from the SQLite database. + # @return [Array<Component>] def components; Component.all; end + + # Retrieve a single {Component} by UUID from the SQLite database. + # @return [Shard] def component(uuid); Component.find_by_uuid uuid; end + + # Retrieve the mapping from component name to {Component}. + # @return [Hash] def available_components; Configuration.available_components; end end end # Load the models