app_config 0.2.3 → 0.2.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.
data/README ADDED
@@ -0,0 +1,48 @@
1
+ = AppConfig
2
+
3
+ An easy to use, customizable library to easily store and retrieve application
4
+ (or library) configuration, API keys or basically anything in 'key/value' pairs.
5
+
6
+
7
+ == Usage
8
+
9
+ Usage is simple. Just pass either a hash of options, or a block, to
10
+ AppConfig.setup. See AppConfig::Base for a list of valid storage methods.
11
+
12
+ For example, given this YAML file:
13
+
14
+ ---
15
+ admin_email: 'admin@example.com'
16
+ api_name: 'Supr Webz 2.0'
17
+ api_key: 'SUPERAWESOMESERVICE'
18
+
19
+ Use it like so:
20
+
21
+ require 'app_config'
22
+
23
+ AppConfig.setup do |config|
24
+ config[:storage_method] = :yaml
25
+ config[:path] = '/path/to/app_config.yml'
26
+ end
27
+
28
+ # Later on...
29
+ # Strings or symbols as keys.
30
+ AppConfig['admin_email'] # => 'admin@example.com'
31
+ AppConfig[:api_name] # => 'Supr Webz 2.0'
32
+ AppConfig[:api_key] # => 'SUPERAWESOMESERVICE'
33
+
34
+ Want SQLite3? No problem!
35
+
36
+ AppConfig.setup do |config|
37
+ config[:storage_method] = :sqlite
38
+ config[:database] = '/path/to/database.sqlite3'
39
+ config[:table] = 'app_config'
40
+ end
41
+
42
+ AppConfig[:column] # => 'value'
43
+
44
+ You can also pass a <tt>:uri</tt> option, which will automatically determine
45
+ the options for the storage method. So in the block (or passed in hash):
46
+
47
+ config[:uri] = 'sqlite://path/to/database.sqlite3'
48
+ config[:uri] = 'yaml://path/to/app_config.yml'
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ FileList[File.dirname(__FILE__) + '/tasks/**/*.rake'].each { |task| load task }
4
+
5
+ task :default => [:spec]
6
+
7
+ desc 'Start an irb session with AppConfig loaded'
8
+ task :console do
9
+ sh "irb -I ./lib -r 'app_config'"
10
+ end
@@ -0,0 +1,61 @@
1
+ module AppConfig
2
+
3
+ # The Base storage class.
4
+ # Acts as a wrapper for the different storage methods.
5
+ #
6
+ # See each storage method's documentation for their specific options.
7
+ #
8
+ # Valid storage methods:
9
+ # * :sqlite (AppConfig::Storage::Sqlite)
10
+ # * :yaml (AppConfig::Storage::YAML)
11
+ class Base
12
+
13
+ # TODO: Change the default storage method to not use YAML.
14
+ DEFAULTS = {
15
+ :storage_method => :yaml,
16
+ }
17
+
18
+ # Accepts either a hash of +options+ or a block (which overrides
19
+ # any options passed in the hash).
20
+ def initialize(options = {}, &block)
21
+ @options = DEFAULTS.merge(options)
22
+ yield @options if block_given?
23
+ determine_storage_method if @options[:uri]
24
+ @storage = initialize_storage
25
+ end
26
+
27
+ # Access the <tt>key</tt>'s value in @storage.
28
+ def [](key)
29
+ @storage[key]
30
+ end
31
+
32
+ private
33
+
34
+ # Sets the storage_method depending on the URI given.
35
+ def determine_storage_method
36
+ uri = URI.parse(@options.delete(:uri))
37
+ case uri.scheme
38
+ when 'sqlite'
39
+ @options[:storage_method] = :sqlite
40
+ @options[:database] = uri.path
41
+ when 'yaml'
42
+ @options[:storage_method] = :yaml
43
+ @options[:path] = uri.path
44
+ end
45
+ end
46
+
47
+ # This decides how to load the data, based on the +storage_method+.
48
+ # TODO: Maybe purge AppConfig options (ie, those not related to the user-end).
49
+ def initialize_storage
50
+ case @options[:storage_method]
51
+ when :sqlite
52
+ AppConfig::Storage::Sqlite.load(@options)
53
+ when :yaml
54
+ AppConfig::Storage::YAML.load(@options)
55
+ else
56
+ raise UnknownStorageMethod
57
+ end
58
+ end
59
+
60
+ end # Base
61
+ end # AppConfig
@@ -0,0 +1,59 @@
1
+ module AppConfig
2
+ module Storage
3
+
4
+ # SQLite3 storage method.
5
+ class Sqlite
6
+ attr_accessor :data
7
+
8
+ DEFAULTS = {
9
+ :database => File.expand_path(File.join(ENV['HOME'], '.app_config.sqlite3')),
10
+ :table => 'app_config'
11
+ }
12
+
13
+ # Loads @data with the SQLite3 database located at +path+.
14
+ # @data will be the Hashish that is accessed like AppConfig[:key].
15
+ #
16
+ # Defaults to $HOME/.app_config.sqlite3
17
+ def initialize(options)
18
+ @options = DEFAULTS.merge(options)
19
+ @db = SQLite3::Database.open(@options[:database])
20
+ @data = load_from_database
21
+ end
22
+
23
+ # Creates a new Sqlite storage with the given +path+ and returns the data.
24
+ def self.load(path)
25
+ new(path).data
26
+ end
27
+
28
+ private
29
+
30
+ # Returns a Hashish that looks something like {:column => value}.
31
+ # TODO: This could use a bit of work.
32
+ def load_from_database
33
+ query = ["SELECT * FROM sqlite_master",
34
+ "WHERE type == 'table' AND name == '#{@options[:table]}'",
35
+ "AND name != 'sqlite_sequence'"].join(' ')
36
+ table = @db.get_first_row(query).last
37
+ values(columns(table))
38
+ end
39
+
40
+ def values(columns)
41
+ data = Hashish.new
42
+ query = "SELECT #{columns.join(', ')} FROM #{@options[:table]}"
43
+ @db.get_first_row(query).each_with_index do |value, index|
44
+ data[columns[index]] = value
45
+ end
46
+ data
47
+ end
48
+
49
+ def columns(table)
50
+ columns = table.split(', ')
51
+ # Trip the first element, since it's the SQL CREATE statement.
52
+ columns = columns[1, columns.size]
53
+ # Yes, Ruby is 'elegant', but this is fucking disgusting. There *must* be a better way.
54
+ columns.map! {|c| c.split('"').reject {|e| e.empty? }.reject {|e| e.include? '('}}.flatten!
55
+ end
56
+
57
+ end # Sqlite
58
+ end # Storage
59
+ end # AppConfig
@@ -0,0 +1,29 @@
1
+ module AppConfig
2
+ module Storage
3
+
4
+ # YAML storage method.
5
+ class YAML
6
+ attr_reader :data
7
+
8
+ DEFAULTS = {
9
+ :path => File.expand_path(File.join(ENV['HOME'], '.app_config.yml'))
10
+ }
11
+
12
+ # Loads @data with the YAML file located at +path+.
13
+ # @data will be the Hashish that is accessed with AppConfig[:key].
14
+ #
15
+ # Defaults to $HOME/.app_config.yml
16
+ def initialize(options)
17
+ path = options[:path] || DEFAULTS[:path]
18
+ # Make sure to use the top-level YAML module here.
19
+ @data = Hashish.new(::YAML.load_file(path))
20
+ end
21
+
22
+ # Creates a new YAML storage with the given +path+ and returns the data.
23
+ def self.load(path)
24
+ new(path).data
25
+ end
26
+
27
+ end # YAML
28
+ end # Storage
29
+ end # AppConfig
@@ -0,0 +1,6 @@
1
+ module AppConfig
2
+ module Storage
3
+ autoload :Sqlite, 'app_config/storage/sqlite'
4
+ autoload :YAML, 'app_config/storage/yaml'
5
+ end
6
+ end
data/lib/app_config.rb ADDED
@@ -0,0 +1,44 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ # TODO: Only load deps if needed (no gems unless required).
4
+ libs = %w{ sqlite3 yaml uri }
5
+
6
+ begin
7
+ libs.each { |lib| require lib }
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ libs.each { |lib| require lib }
11
+ end
12
+
13
+ require 'core_ext/hashish'
14
+
15
+ # TODO: Move these to their own file.
16
+ class NotConfigured < Exception
17
+ def to_s; "Must call 'AppConfig.setup' to setup storage!"; end
18
+ end
19
+ class UnknownStorageMethod < Exception; end
20
+
21
+ module AppConfig
22
+ VERSION = '0.2.4'
23
+
24
+ autoload :Base, 'app_config/base'
25
+ autoload :Storage, 'app_config/storage'
26
+
27
+ # Returns the AppConfig version string.
28
+ def self.to_version
29
+ "#{self.class} v#{VERSION}"
30
+ end
31
+
32
+ # Access the configured <tt>key</tt>'s value.
33
+ def self.[](key)
34
+ raise NotConfigured unless defined?(@@storage)
35
+ @@storage[key]
36
+ end
37
+
38
+ # Accepts an +options+ hash or a block.
39
+ # See AppConfig::Base for valid storage methods.
40
+ def self.setup(options = {}, &block)
41
+ @@storage = AppConfig::Base.new(options, &block)
42
+ end
43
+
44
+ end # AppConfig
@@ -0,0 +1,137 @@
1
+ # Stolen from Rails Active Support and aliased to Hashish.
2
+ #
3
+ # This class has dubious semantics and we only have it so that
4
+ # people can write params[:key] instead of params['key']
5
+ # and they get the same value for both keys.
6
+ class HashWithIndifferentAccess < Hash
7
+ def initialize(constructor = {})
8
+ if constructor.is_a?(Hash)
9
+ super()
10
+ update(constructor)
11
+ else
12
+ super(constructor)
13
+ end
14
+ end
15
+
16
+ def default(key = nil)
17
+ if key.is_a?(Symbol) && include?(key = key.to_s)
18
+ self[key]
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
25
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
26
+
27
+ # Assigns a new value to the hash:
28
+ #
29
+ # hash = HashWithIndifferentAccess.new
30
+ # hash[:key] = "value"
31
+ #
32
+ def []=(key, value)
33
+ regular_writer(convert_key(key), convert_value(value))
34
+ end
35
+
36
+ # Updates the instantized hash with values from the second:
37
+ #
38
+ # hash_1 = HashWithIndifferentAccess.new
39
+ # hash_1[:key] = "value"
40
+ #
41
+ # hash_2 = HashWithIndifferentAccess.new
42
+ # hash_2[:key] = "New Value!"
43
+ #
44
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
45
+ #
46
+ def update(other_hash)
47
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
48
+ self
49
+ end
50
+
51
+ alias_method :merge!, :update
52
+
53
+ # Checks the hash for a key matching the argument passed in:
54
+ #
55
+ # hash = HashWithIndifferentAccess.new
56
+ # hash["key"] = "value"
57
+ # hash.key? :key # => true
58
+ # hash.key? "key" # => true
59
+ #
60
+ def key?(key)
61
+ super(convert_key(key))
62
+ end
63
+
64
+ alias_method :include?, :key?
65
+ alias_method :has_key?, :key?
66
+ alias_method :member?, :key?
67
+
68
+ # Fetches the value for the specified key, same as doing hash[key]
69
+ def fetch(key, *extras)
70
+ super(convert_key(key), *extras)
71
+ end
72
+
73
+ # Returns an array of the values at the specified indices:
74
+ #
75
+ # hash = HashWithIndifferentAccess.new
76
+ # hash[:a] = "x"
77
+ # hash[:b] = "y"
78
+ # hash.values_at("a", "b") # => ["x", "y"]
79
+ #
80
+ def values_at(*indices)
81
+ indices.collect {|key| self[convert_key(key)]}
82
+ end
83
+
84
+ # Returns an exact copy of the hash.
85
+ def dup
86
+ HashWithIndifferentAccess.new(self)
87
+ end
88
+
89
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
90
+ # Does not overwrite the existing hash.
91
+ def merge(hash)
92
+ self.dup.update(hash)
93
+ end
94
+
95
+ # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
96
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
97
+ def reverse_merge(other_hash)
98
+ super other_hash.with_indifferent_access
99
+ end
100
+
101
+ def reverse_merge!(other_hash)
102
+ replace(reverse_merge( other_hash ))
103
+ end
104
+
105
+ # Removes a specified key from the hash.
106
+ def delete(key)
107
+ super(convert_key(key))
108
+ end
109
+
110
+ def stringify_keys!; self end
111
+ def symbolize_keys!; self end
112
+ def to_options!; self end
113
+
114
+ # Convert to a Hash with String keys.
115
+ def to_hash
116
+ Hash.new(default).merge!(self)
117
+ end
118
+
119
+ protected
120
+ def convert_key(key)
121
+ key.kind_of?(Symbol) ? key.to_s : key
122
+ end
123
+
124
+ def convert_value(value)
125
+ case value
126
+ when Hash
127
+ value.with_indifferent_access
128
+ when Array
129
+ value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
130
+ else
131
+ value
132
+ end
133
+ end
134
+ end
135
+
136
+ # Simple alias.
137
+ Hashish = HashWithIndifferentAccess
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Campbell
@@ -11,8 +11,17 @@ cert_chain: []
11
11
 
12
12
  date: 2009-09-27 00:00:00 -05:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sqlite3-ruby
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
16
25
  description: An easy to use, customizable library to easily store and retrieve application configuration.
17
26
  email:
18
27
  - oshuma@gmail.com
@@ -22,15 +31,23 @@ extensions: []
22
31
 
23
32
  extra_rdoc_files: []
24
33
 
25
- files: []
26
-
34
+ files:
35
+ - Rakefile
36
+ - README
37
+ - lib/app_config.rb
38
+ - lib/app_config/base.rb
39
+ - lib/app_config/storage.rb
40
+ - lib/app_config/storage/sqlite.rb
41
+ - lib/app_config/storage/yaml.rb
42
+ - lib/core_ext/hashish.rb
27
43
  has_rdoc: true
28
44
  homepage: http://oshuma.github.com/app_config
29
45
  licenses: []
30
46
 
31
47
  post_install_message:
32
- rdoc_options: []
33
-
48
+ rdoc_options:
49
+ - --inline-source
50
+ - --charset=UTF-8
34
51
  require_paths:
35
52
  - lib
36
53
  required_ruby_version: !ruby/object:Gem::Requirement