app_config 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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