Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

configtoolkit

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

configtoolkit

  • 2.3.2
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source

= configtoolkit

  • Project Page: http://rubyforge.org/projects/configtoolkit/

== DESCRIPTION: This package makes sourcing information from (parsing) configuration files robust and easy! It:

  • Allows programmers to specify the type of data that should be loaded from a configuration file. The toolkit automatically will validate the file's data against this specification when loading the file, ensuring that the specification always is obeyed and saving the programmer the tedious chore of writing validation code.
  • Automagically generates parameter accessor methods (getters, setters, and predicates to test for presence), an equality operator, and a +to_s+ method from the configuration's specification.
  • Allows programmers to create configuration files, easily and programatically.
  • Provides a class that can load (parse) Ruby configuration files (allowing the full power of Ruby to be used within configuration files).
  • Provides classes that can load from (parse) and dump to YAML and key-value configuration files.
  • Provides classes that can load from and dump to Hashes.
  • Provides a class that allows the contents of one configuration source to override the contents of another (this works with configuration files of any format or Hashes).
  • Is very extensible, allowing the engine to be used with custom format configuration files and with custom data validation rules.

== FEATURES:

  • The ConfigToolkit allows programmers to define a new configuration class by specifying the parameters that are included in the configuration. A parameter specification consists of the class of the parameter's values, whether or not the paramater is required, and a default value if the parameter is not required.
  • Getter, setter, and predicate methods automatically are generated for a new configuration class for each specified parameter to get the parameter's value, set the parameter's value, and test whether the parameter has a value.
  • A method to clear a parameter's value automatically is generated for optional parameters.
  • A block can be passed to the +new+ method of a configuration class in order to initialize the instance (see ConfigToolkit::BaseConfig.new).
  • The ConfigToolkit (by default) will print warnings when it encounters unknown configuration parameters, allowing errors in configuration files to be discovered quickly.
  • The behavior of the ConfigToolkit for a particular ConfigToolkit::BaseConfig child class or for an instance of a ConfigToolkit::BaseConfig child class can be configured through specifying a ConfigToolkit::ConfigToolkitConfig. Right now, the ConfigToolkit's behavior when it encounters an unknown parameter can be configured (to ignore the unknown parameter, to warn about the unknown parameter, or to raise an error about the unknown parameter).
  • +rdoc+ can detect and generate documentation for each parameter in a configuration class (see FAQ.txt for how to enable this).
  • An equality operator exists for each configuration class that determines equality based on whether all parameter values are equal.
  • A +to_s+ method that produces very pretty output exists for each configuration class (ConfigToolkit::BaseConfig#to_s, leveraging the ConfigToolkit::PrettyPrintWriter)
  • Programmers can specify custom validation blocks for each parameter, in order to enforce specifications not directly supported by the engine.
  • Programmers can define a method in a configuration class that will be called in order to enforce relationships between the values of different parameters (ConfigToolkit::BaseConfig#validate_all_values)
  • Programmers can create custom reader and writer classes in order to load from and dump to (respectively) configuration file formats not directly supported by the ConfigToolkit.
  • Configuration classes can be nested to any depth within each other.
  • Configuration classes have first class support for Array configuration parameters. Constraints can be specified for a given Array parameter that will ensure that all elements are of a specified class and that there are a specified number of elements present (see ConfigToolkit::ConstrainedArray)
  • The ConfigToolkit supports multiple configurations stored in a single file; it is able to distinguish that different configurations within a file belong to different configuration objects. For example, "production" and "test" configuration information can live within the same configuration file and can be loaded into separate configuration instances (by specifying a different "containing object name" for each ConfigToolkit::BaseConfig#load call)
  • A reader class to read (parse) Ruby configuration files (ConfigToolkit::RubyReader)
  • A reader class to read (parse) YAML configuration files (ConfigToolkit::YAMLReader)
  • A writer class to dump YAML configuration files (ConfigToolkit::YAMLWriter)
  • A reader class to load configuration directly from a Hash (ConfigToolkit::HashReader)
  • A writer class do dump configuration directly to a Hash (ConfigToolkit::HashWriter)
  • A reader class to read (parse) key-value configuration files (ConfigToolkit::KeyValueReader)
  • A writer class to dump key-value configuration files (ConfigToolkit::KeyValueWriter)
  • The ConfigToolkit::KeyValueReader and ConfigToolkit::KeyValueWriter classes can be configured to work with many different formats of key-value configuration files (via ConfigToolkit::KeyValueConfig).
  • A reader class to source one configuration from multiple configuration files, allowing one configuration file to override another (ConfigToolkit::OverrideReader)
  • The ConfigToolkit includes a full unit testing suite.
  • The ConfigToolkit code has detailed comments.
  • The ConfigToolkit code has many example programs (in the +examples+ subdirectory).
  • The ConfigToolkit package includes extensive documentation, including FAQ.txt and documentation for the support file formats.

== PROBLEMS: None (known).

== SYNOPSIS: Here is a sample configuration class: ======examples/machineconfig.rb: require 'rubygems' require 'configtoolkit'

require 'uri'

This configuration class is nested within MachineConfig (below).

All configuration classes must descend from ConfigToolkit::BaseConfig.

class OSConfig < ConfigToolkit::BaseConfig add_required_param(:name, String) add_required_param(:version, Float) end

This configuration class is used in all of the example programs.

Since it is a configuration class, it descends from

ConfigToolkit::BaseConfig.

class MachineConfig < ConfigToolkit::BaseConfig

This is a required parameter with extra user-specified validation

(that :num_cpus > 0 must be true)

add_required_param(:num_cpus, Integer) do |value| if(value <= 0) raise_error("num_cpus must be greater than zero") end end

This required parameter is itself a BaseConfig instance; BaseConfig

instances can be nested within each other.

add_required_param(:os, OSConfig)

This is a required boolean parameter. Note that Ruby does not

have a boolean type (it has a TrueClass and a FalseClass), so use

a marker class (ConfigToolkit::Boolean) to indicate that

the parameter will have boolean values (true and false).

Boolean values can be written as "true"/"false" or as

"yes"/"no" in configuration files.

add_required_param(:contains_sensitive_data, ConfigToolkit::Boolean)

The behind_firewall parameter is optional and has a default value of

true, which means that it will be set to the true if not explicitly set

by a configuration file.

add_optional_param(:behind_firewall, ConfigToolkit::Boolean, true)

The primary_contact parameter is optional and has no default value, which

means that it will be absent if not explicitly set by a configuration file.

add_optional_param(:primary_contact, String)

This parameter's values are guaranteed to be Arrays with URI elements.

add_required_param(:addresses, ConfigToolkit::ConstrainedArray.new(URI))

This method is called by load() after loading values for

all parameters from a specified configuration and can enforce

constraints between different parameters. In this case, this method

ensures that all machines containing sensitive data are behind

the firewall.

def validate_all_values if(contains_sensitive_data && !behind_firewall) raise_error("only machines behind firewalls can contain sensitive data") end end end

This code creates a configuration class for a company's servers by subclassing ConfigToolkit::BaseConfig. Each of the parameters is specified (the parameter's class, whether the parameter is required, and a default value if the parameter is optional) with private class methods of ConfigToolkit::BaseConfig (ConfigToolkit::BaseConfig.add_required_param and ConfigToolkit::BaseConfig.add_optional_param).

A +validate_all_values+ method also is defined in the +MachineConfig+ class that enforces an invariant between multiple parameters. This will be called at the end of ConfigToolkit::BaseConfig#load or at the start of ConfigToolkit::BaseConfig#dump (see ConfigToolkit::BaseConfig#validate_all_values for more details).

A custom validation block is specified for the +num_cpus+ parameter; the ConfigToolkit engine does not have direct support for checking specifications like "the value must be greater than zero", but these conditions easily can be added by the programmer. Such blocks are called by the engine before the configuration parameter is set to the new value and are executed in the context of the configuration class instance. If there is a problem with the new value, the block should call ConfigToolkit::BaseConfig#raise_error.

A ConfigToolkit::Boolean class is specified for the +behind_firewall+ and +contains_sensitive_data+ parameters. Ruby does not have a standard boolean class (although it does have TrueClass and FalseClass, for boolean values), and so the ConfigToolkit provides a marker class for boolean values. The value of a parameter specified with ConfigToolkit::Boolean either is +true+ or +false+.

A ConfigToolkit::ConstrainedArray.new(URI) class is specified for the +addresses+ parameter. A ConfigToolkit::ConstrainedArray class simply specifies that the parameter value will be an Array that obeys the constraints contained in the ConfigToolkit::ConstrainedArray. In this case, the constraints ensure that all Array elements are of class URI, that the Array has at least two elements. Additional constraints on the number of elements in the Array are possible

The following program manipulates a MachineConfig instance. ======examples/usage_example.rb: #!/usr/bin/env ruby

These example programs use the 'relative' gem in order to

express paths relative to FILE cleanly, allowing them to be run from

any directory. In particular, they use the require_relative

method to load examples/machineconfig.rb and

File.expand_path_relative_to_caller in order to refer to

configuration files within the examples directory.

require 'rubygems' require 'relative' require_relative 'machineconfig'

If new() is passed a block, the block must initialize all

required parameters (otherwise a ConfigToolkit::Error will

be thrown). Optional parameters to not need to be

explicitly initialized, however. If a default value was

specified for an uninitialized optional parameter, the

optional parameter will be set to the default value after

the block (the behind_firewall parameter is an example of this below);

otherwise, the default value will have no value

(the primary_contact parameter is an example of this below).

config = MachineConfig.new() do |config| config.num_cpus = 8 config.os = OSConfig.new() do |os_config| os_config.name = "Solaris" os_config.version = 10.0 end config.contains_sensitive_data = true config.addresses = [URI("http://www.designingpatterns.com"), URI("http://jackfruit.designingpatterns.com")] end

Note in the output that the behind_firewall parameter is true, its

default value, because it was not initialized in the block above.

Also note that the primary_contact parameter is not present.

print "Config after initialization:\n#{config}\n"

Each parameter has a predicate method (automatically generated by

add_required_param or add_optional_param) that returns whether or not

the parameter has a value.

if(!config.primary_contact?)

This will be printed...

print "Optional primary_contact parameter is NOT set!\n" end

Each parameter has getter and setter accessor methods (automatically

generated by add_required_param or add_optional_param), just like

"normal" attributes.

config.primary_contact = "Tony" print("primary_contact parameter set to: #{config.primary_contact}\n")

if(config.primary_contact?)

This will be printed...

print "Optional primary_contact parameter is now IS set!\n\n" end

Note in the output that the primary_contact parameter now is present.

print "Config after setting optional primary_contact parameter:\n#{config}\n"

Each optional parameter has a clear method (automatically generated by

add_optional_param) that deletes the parameter's value.

config.clear_primary_contact()

if(!config.primary_contact?)

This will be printed...

print "Optional primary_contact parameter has been deleted!\n\n" end

Note in the output that the primary_contact parameter once again

is absent.

print "Config after deleting the primary_contact parameter:\n#{config}\n"

This example uses the accessor methods (a getter, a setter, and a predicate) that are generated automatically for each configuration parameter. These allow configuration instances to be manipulated in the same way that instances of a hand-written configuration class could be manipulated. Note, however, that the same strict validation is performed for values specified programatically through setters as is done for values sourced from configuration files. Also note that setters copy the values of their arguments (with the +dup+ method) not references to their arguments, unlike the setters created by the +attr_accessor+ method. When run, it produces: ======The output of examples/usage_example.rb: Config after initialization: { contains_sensitive_data: true num_cpus : 8 addresses : [ http://www.designingpatterns.com, http://jackfruit.designingpatterns.com ] os : { version: 10.0 name : Solaris } behind_firewall : true }

Optional primary_contact parameter is NOT set! primary_contact parameter set to: Tony Optional primary_contact parameter is now IS set!

Config after setting optional primary_contact parameter: { contains_sensitive_data: true num_cpus : 8 addresses : [ http://www.designingpatterns.com, http://jackfruit.designingpatterns.com ] os : { version: 10.0 name : Solaris } behind_firewall : true primary_contact : Tony }

Optional primary_contact parameter has been deleted!

Config after deleting the primary_contact parameter: { contains_sensitive_data: true num_cpus : 8 addresses : [ http://www.designingpatterns.com, http://jackfruit.designingpatterns.com ] os : { version: 10.0 name : Solaris } behind_firewall : true }

Of course, the most common use case will be setting configuration parameters with the contents of configuration files, not programatically. The following YAML configuration file contains two MachineConfig configurations: ======examples/load_example.yaml:

This file contains MachineConfig configurations

(see examples/machineconfig.rb for the configuration's specification).

############################################################

First configuration

num_cpus: 32 os: name: AIX version: 5.3 behind_firewall: no contains_sensitive_data: no addresses:

production is a containing object

production:

production.www is a containing object

www: ############################################################

Second configuration (nested in the production.www

containing object)

 num_cpus: 64
 os:
   name: Solaris
   version: 10.0
 contains_sensitive_data: yes
 addresses:
   - http://www.designingpatterns.com
   - http://tokyo.designingpatterns.com

############################################################

The following program loads and prints the two configurations from +examples/load_example.yaml+. ======examples/load_example.rb: #!/usr/bin/env ruby

These example programs use the 'relative' gem in order to

express paths relative to FILE cleanly, allowing them to be run from

any directory. In particular, they use the require_relative

method to load examples/machineconfig.rb and

File.expand_path_relative_to_caller in order to refer to

configuration files within the examples directory.

require 'rubygems' require 'relative' require_relative 'machineconfig'

require 'configtoolkit/yamlreader'

CONFIGURATION_FILE = File.expand_path_relative_to_caller("load_example.yaml")

The first configuration has no containing object name.

reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE) first_config = MachineConfig.load(reader) print("The first config:\n#{first_config}\n")

The second configuration has "production.www" as a containing

object name.

reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE) second_config = MachineConfig.load(reader, "production.www") print("The second config:\n#{second_config}\n")

Note how the program changes the containing object name passed to the +load+ method (first an empty string, next +production.www+, and finally +production.mail+) in order to refer to different configurations within the YAML file. The ConfigToolkit's support of containing objects allows it to accomodate multiple configurations living in the same file, with each configuration being accessible separately. When run, it produces: ======The output of examples/load_example.rb: The first config: { addresses : [ http://default.designingpatterns.com, http://apple.designingpatterns.com ] contains_sensitive_data: false os : { version: 5.3 name : AIX } behind_firewall : false num_cpus : 32 }

The second config: production.www: { addresses : [ http://www.designingpatterns.com, http://tokyo.designingpatterns.com ] contains_sensitive_data: true os : { version: 10.0 name : Solaris } behind_firewall : true num_cpus : 64 }

A group of configurations also can be loaded with the ConfigToolkit::BaseConfig.load_group method. For instance, given +examples/load_group_example.yaml+: ======examples/load_group_example.yaml:

This file contains MachineConfig configurations

(see examples/machineconfig.rb for the configuration's specification).

db_cluster: db1: num_cpus: 16 os: name: Solaris version: 10.0 contains_sensitive_data: yes behind_firewall: yes addresses: - http://db1.designingpatterns.com db2: num_cpus: 12 os: name: AIX version: 5.3 contains_sensitive_data: yes behind_firewall: yes addresses: - http://db2.designingpatterns.com db3: num_cpus: 24 os: name: Solaris version: 10.0 contains_sensitive_data: yes behind_firewall: yes addresses: - http://db3.designingpatterns.com

the following code will load the file's three configurations into a +Hash+ mapping containing object names to configurations: ======examples/load_group_example.rb: #!/usr/bin/env ruby

These example programs use the 'relative' gem in order to

express paths relative to FILE cleanly, allowing them to be run from

any directory. In particular, they use the require_relative

method to load examples/machineconfig.rb and

File.expand_path_relative_to_caller in order to refer to

configuration files within the examples directory.

require 'rubygems' require 'relative' require_relative 'machineconfig'

require 'configtoolkit/yamlreader'

CONFIGURATION_FILE = File.expand_path_relative_to_caller("load_group_example.yaml")

The group of configurations is under the db_cluster containing

object name.

reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE) configs = MachineConfig.load_group(reader, "db_cluster") configs.each do |name, config| print "The #{name} configuration:\n#{config}\n" end

When run, it produces: ======The output of examples/load_group_example.rb: The db3 configuration: db_cluster.db3: { addresses : [ http://db3.designingpatterns.com ] contains_sensitive_data: true os : { name : Solaris version: 10.0 } behind_firewall : true num_cpus : 24 }

The db1 configuration: db_cluster.db1: { addresses : [ http://db1.designingpatterns.com ] contains_sensitive_data: true os : { name : Solaris version: 10.0 } behind_firewall : true num_cpus : 16 }

The db2 configuration: db_cluster.db2: { addresses : [ http://db2.designingpatterns.com ] contains_sensitive_data: true os : { name : AIX version: 5.3 } behind_firewall : true num_cpus : 12 }

== CONFIGURING THE CONFIGTOOLKIT As of version 2.3.0, the ConfigToolkit itself can be configured.

Consider the following simple YAML configuration file: ======examples/config_toolkit_config_example.yaml: name: Tony

'country' has been misspelled

county: USA

The following code configures the +SimpleConfig+ class and specific instances of the +SimpleConfig+ class to behave differently than the ConfigToolkit default when unknown parameters are encountered when loading a configuration file. ======examples/config_toolkit_config_example.rb: #!/usr/bin/env ruby

require 'rubygems' require 'configtoolkit' require 'configtoolkit/yamlreader'

require 'relative'

class SimpleConfig < ConfigToolkit::BaseConfig

Set SimpleConfig's default ConfigToolkit::ConfigToolkitConfig via

the default_config_toolkit_config accessor method.

self.default_config_toolkit_config = ConfigToolkit::ConfigToolkitConfig.new() do |instance| # # This will suppress warnings when an unknown config param # is encountered when loading a configuration file. # instance.unknown_config_param_behavior = ConfigToolkit::ConfigToolkitConfig::UnknownConfigParamBehavior::IGNORE end

add_required_param(:name, String)

add_optional_param(:country, String, NO_DEFAULT_VALUE)

end

CONFIGURATION_FILE = File.expand_path_relative_to_caller("config_toolkit_config_example.yaml")

Even though there is a bogus parameter in the configuration file,

SimpleConfig.load silently will ignore it due to SimpleConfig's

default ConfigToolkit::ConfigToolkitConfig.

reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE) config = SimpleConfig.load(reader) puts "Unknown parameters silently were ignored when loading this: #{config}\n"

Note that a ConfigToolkit::ConfigToolkitConfig is passed

into SimpleConfig.load below. This will override SimpleConfig's default

ConfigToolkit::ConfigToolkitConfig and cause an error to be raised when

the unknown parameter is encountered.

config_toolkit_config = ConfigToolkit::ConfigToolkitConfig.new() do |instance|

This will cause an error to be raised when an unknown config param

is encountered when loading a configuration file.

instance.unknown_config_param_behavior = ConfigToolkit::ConfigToolkitConfig::UnknownConfigParamBehavior::ERROR end reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE)

begin config = SimpleConfig.load(reader, "", config_toolkit_config) rescue ConfigToolkit::Error => e puts e end

When run, it produces: ======The output of examples/config_toolkit_config_example.rb: Unknown parameters silently were ignored when loading this: { name: Tony }

error setting county with value USA: no parameter county exists for configuration class SimpleConfig.

=== CONFIGTOOLKIT CONFIGURATION PARAMETERS +unknown_config_param_behavior+: the behavior when encountering an unknown parameter. Its possible values: +ignore+:: The unknown parameter will be ignored (+ignore+). This can be useful in order to maintain compatibility with older versions of software when adding new fields to a configuration file. +warn+:: The unknown parameter will cause a warning to be issued (+warn+). This is the default and can allow errors in configuration files to be detected more easily. It does NOT prevent the configuration file from being loaded, however. +error+:: The unknown parameter will cause an error to be raised, preventing the configuration file from being loaded.

== CONFIGURATION FILE FORMATS: === EXISTING FORMATS:

  • YAML.txt describes working with YAML configuration files.
  • KeyValue.txt describes working with key-value configuration files.
  • Ruby.txt describes working with Ruby configuration files.
  • Hash.txt describes loading configurations from Hashes and dumping configurations to Hashes.
  • Override.txt describes loading configurations from multiple sources (files), allowing the configuration from one source to override that from another source.

=== NEW FORMATS: The ConfigToolkit easily can be extended to support new file formats. A new reader class can be created to load from a new format, and a new writer class can be created to write out a new format.

The reader interface is documented by the ConfigToolkit::Reader class. Basically, a reader needs to have a read method that reads data from some underlying stream and returns a Hash that represents the configuration (see ConfigToolkit::Reader#read for the specifications; ConfigToolkit::YAMLReader#read is a simple example of an implementation). ConfigToolkit::HashReader is a no-op reader, so the Hash that its constructor accepts is the same that a new reader class should return from its +read+ method.

The writer interface is documented by the ConfigToolkit::Writer class. Basically, a writer needs to have a write method that accepts a Hash representing a configuration and writes it to some underlying stream (see ConfigToolkit::Writer#write for the specifications; ConfigToolkit::YAMLWriter#write is a relatively simple example of an implementation). ConfigToolkit::HashWriter is a no-op writer, so the Hash stored in its +config_hash+ attribute after a ConfigToolkit::BaseConfig#dump call is the same Hash passed to a writer's +write+ method.

While writing a new reader or writer class, it may be necessary to iterate over a Hash that contains arbitrarily deeply nested Hashes and Arrays. The ConfigToolkit::HashArrayVisitor can help with this task by allowing hook functions to be written that will be called when a particular type of node is visited. ConfigToolkit::YAMLWriter#write, ConfigToolkit::KeyValueWriter#write and ConfigToolkit::PrettyPrintWriter#write all use such visitors.

Feel free also to request that we add support for a new file format to the distribution, and we will try our best to accomodate! See below for some ideas that we have had for new readers and writers.

== CONFIGURATION CLASS DOCUMENTATION: Configuration classes can be documented properly by +rdoc+, although not by default. See FAQ.txt for full details.

== REQUIREMENTS: Hoe, assertions, and relative are required, but only for running the tests. Relative also is required for running the examples.

== INSTALL: sudo gem install configtoolkit

== POSSIBLE FUTURE TECHNICAL DIRECTIONS: Here are some possible ideas:

  • Modify the ConfigToolkit and/or +rdoc+ so that +rdoc+ produces good documentation for configuration classes (perhaps showing parameter value classes and any default values). This enhancement should eliminate any need to patch +rdoc+ (see FAQ.txt for the current procedure).
  • Provide support for sourcing configuration from XML files (+XMLReader+ and +XMLWriter+ classes)
  • Provide support for sourcing configuration from INI files (+INIReader+ and +INIWriter+ classes)
  • Provide support for sourcing configuration from command-line parameters (+CommandLineReader+ and +CommandLineWriter+ classes)
  • Provide support for sourcing configuration from environment variables (+EnvVarReader+ and +EnvVarWriter+ classes)
  • Provide support for sourcing configuration from a database (+DatabaseReader+ and +DatabaseWriter+ classes)
  • Provide support for sourcing configuration from a configuration file (of any format) containing embedded Ruby (+EmbeddedRubyReader+ class, which would process the embedded Ruby and then hand the resulting file off to another reader class)
  • Allow more powerful parameter specifications to be specified. For instance, it would be nice if users could specify that the parameter is a Pathname to a readable file. Possibly the ConfigToolkit should provide a Rules interface to create new parameter rules.
  • Allow user-specified conversions from Strings to arbitrary types for configuration file formats that only have a limited type palette (key-value files, for instance).
  • Allow other languages to use the ConfigToolkit (possible targets could be C++, Python, or Java)
  • Provide a ConfigToolkit::BaseConfig class method "constructor" that would allocate any nested config instances and Arrays (recursively, so that and multiply-nested config instances and Arrays also would be initialized). This would make programatically setting the configuration parameters very easy, since no explicit +new+ calls would be necessary for the nested config object and Array parameters.

We would love to receive input from users about which new features are most desirable!

== AUTHORS: === Designing Patterns

== SUPPORT: Please post questions, concerns, or requests for enhancement to the forums on the project page. Alternatively, direct contact information for Designing Patterns can be found on the project page for this gem.

== ENHANCEMENTS: Please feel free to contact us with any ideas; we will try our best to enhance the software and respond to user requests. Of course, we are more likely to work on a particular enhancement if we know that there are users who want it. Designing Patterns provides contracting and consulting services, so if there is an enhancement that must get done (and in a specified time frame), please inquire about retaining our services!

== LICENSE: The license text can be found in the +LICENSE+ file at the root of the distribution.

This package is licensed with an MIT license:

Copyright (c) 2008-2009 Designing Patterns

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

== SHARE AND ENJOY!

FAQs

Package last updated on 02 May 2011

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc