pwnbus-configdb 0.1.0
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/.document +11 -0
- data/.gitignore +42 -0
- data/.project +12 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/pwnbus/configdb.rb +47 -0
- data/lib/pwnbus/configdb/db.rb +160 -0
- data/lib/pwnbus/configdb/files.rb +159 -0
- data/pwnbus-configdb.gemspec +83 -0
- data/spec/.rspec +1 -0
- data/spec/db_object_spec.rb +54 -0
- data/spec/db_spec.rb +166 -0
- data/spec/fixtures/db.yml +3 -0
- data/spec/spec_helper.rb +20 -0
- metadata +216 -0
data/.document
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# .document is used by rdoc and yard to know how to generate documentation
|
2
|
+
# for example, it can be used to control how rdoc gets built when you do `gem install foo`
|
3
|
+
|
4
|
+
README.rdoc
|
5
|
+
lib/**/*.rb
|
6
|
+
bin/*
|
7
|
+
|
8
|
+
# Files below this - are treated as 'extra files', and aren't parsed for ruby code
|
9
|
+
-
|
10
|
+
features/**/*.feature
|
11
|
+
LICENSE
|
data/.gitignore
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
|
14
|
+
# jeweler generated
|
15
|
+
pkg
|
16
|
+
|
17
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
18
|
+
#
|
19
|
+
# * Create a file at ~/.gitignore
|
20
|
+
# * Include files you want ignored
|
21
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
22
|
+
#
|
23
|
+
# After doing this, these files will be ignored in all your git projects,
|
24
|
+
# saving you from having to 'pollute' every project you touch with them
|
25
|
+
#
|
26
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
27
|
+
#
|
28
|
+
# For MacOS:
|
29
|
+
#
|
30
|
+
#.DS_Store
|
31
|
+
#
|
32
|
+
# For TextMate
|
33
|
+
#*.tmproj
|
34
|
+
#tmtags
|
35
|
+
#
|
36
|
+
# For emacs:
|
37
|
+
#*~
|
38
|
+
#\#*
|
39
|
+
#.\#*
|
40
|
+
#
|
41
|
+
# For vim:
|
42
|
+
#*.swp
|
data/.project
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<projectDescription>
|
3
|
+
<name>pwnbus-configdb</name>
|
4
|
+
<comment></comment>
|
5
|
+
<projects>
|
6
|
+
</projects>
|
7
|
+
<buildSpec>
|
8
|
+
</buildSpec>
|
9
|
+
<natures>
|
10
|
+
<nature>org.radrails.rails.core.railsnature</nature>
|
11
|
+
</natures>
|
12
|
+
</projectDescription>
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", ">= 2.0.0.beta.20"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.5.0.pre3"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.0.pre3)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.9)
|
12
|
+
rspec (2.0.0.beta.22)
|
13
|
+
rspec-core (= 2.0.0.beta.22)
|
14
|
+
rspec-expectations (= 2.0.0.beta.22)
|
15
|
+
rspec-mocks (= 2.0.0.beta.22)
|
16
|
+
rspec-core (2.0.0.beta.22)
|
17
|
+
rspec-expectations (2.0.0.beta.22)
|
18
|
+
diff-lcs (>= 1.1.2)
|
19
|
+
rspec-mocks (2.0.0.beta.22)
|
20
|
+
rspec-core (= 2.0.0.beta.22)
|
21
|
+
rspec-expectations (= 2.0.0.beta.22)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
bundler (~> 1.0.0)
|
28
|
+
jeweler (~> 1.5.0.pre3)
|
29
|
+
rcov
|
30
|
+
rspec (>= 2.0.0.beta.20)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Victor Costan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= pwnbus-configdb
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Victor Costan. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "pwnbus-configdb"
|
16
|
+
gem.summary = %Q{Pure-ruby database for configuration variables.}
|
17
|
+
gem.description = %Q{Dead-simple key-value store with atomic updates.}
|
18
|
+
gem.email = "victor@costan.us"
|
19
|
+
gem.homepage = "http://github.com/pwnall/pwnbus_configdb"
|
20
|
+
gem.authors = ["Victor Costan"]
|
21
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
22
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
23
|
+
# spec.add_runtime_dependency 'jabber4r', '> 0.1'
|
24
|
+
# spec.add_development_dependency 'rspec', '> 1.2.3'
|
25
|
+
gem.add_development_dependency "rspec", ">= 2.0.0.beta.20"
|
26
|
+
gem.add_development_dependency "bundler", "~> 1.0.0"
|
27
|
+
gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
|
28
|
+
gem.add_development_dependency "rcov", ">= 0"
|
29
|
+
end
|
30
|
+
Jeweler::RubygemsDotOrgTasks.new
|
31
|
+
|
32
|
+
require 'rspec/core'
|
33
|
+
require 'rspec/core/rake_task'
|
34
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
35
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
36
|
+
end
|
37
|
+
|
38
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
39
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
40
|
+
spec.rcov = true
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :spec
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "new #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path('../configdb/db.rb', __FILE__)
|
2
|
+
require File.expand_path('../configdb/files.rb', __FILE__)
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Pwnbus
|
6
|
+
|
7
|
+
# Pure-ruby database for configuration variables.
|
8
|
+
module Configdb
|
9
|
+
# Opens a configuration database. The database is created if it doesn't exist.
|
10
|
+
#
|
11
|
+
# Args:
|
12
|
+
# name:: the database name; if the name starts with a ., the database is
|
13
|
+
# only readable to the current user, otherwise it is public (readable
|
14
|
+
# to everyone, but only writable by the current user)
|
15
|
+
# options:: the following keys are recognized
|
16
|
+
# :read:: opens the database only for reading
|
17
|
+
#
|
18
|
+
# Yields a proxy object that can be used to access the database.
|
19
|
+
#
|
20
|
+
# Returns the value produced by the block.
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# Pwnbus::Configdb.open('system') do |system|
|
24
|
+
# system.os.name = 'Ubuntu'
|
25
|
+
# system.os.version = '10.04.1'
|
26
|
+
# end
|
27
|
+
def self.open(name, options = {})
|
28
|
+
db_path = Files.find_db(name) || Files.create_db(name, options)
|
29
|
+
|
30
|
+
db_file = Files.open_db(db_path, options)
|
31
|
+
db = Db.new db_file
|
32
|
+
begin
|
33
|
+
return_value = yield db.proxy
|
34
|
+
if db.dirty?
|
35
|
+
Files.write_db db_path, options do |wf|
|
36
|
+
db.write wf
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return_value
|
40
|
+
ensure
|
41
|
+
db.close
|
42
|
+
db_file.close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # namespace Pwnbus::Configdb
|
46
|
+
|
47
|
+
end # namespace Pwnbus
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
# :nodoc: namespace
|
4
|
+
module Pwnbus
|
5
|
+
|
6
|
+
# :nodoc: file-related functionality
|
7
|
+
module Configdb
|
8
|
+
|
9
|
+
# Database instance.
|
10
|
+
class Db
|
11
|
+
attr_reader :data
|
12
|
+
attr_reader :proxy
|
13
|
+
|
14
|
+
# Database initialized with the contents of a file.
|
15
|
+
#
|
16
|
+
# Args:
|
17
|
+
# file:: File instance
|
18
|
+
def initialize(file)
|
19
|
+
@data = YAML.load file
|
20
|
+
@dirty = false
|
21
|
+
@proxy = Proxy.new self, ''
|
22
|
+
end
|
23
|
+
|
24
|
+
# Writes the database contents to a file.
|
25
|
+
#
|
26
|
+
# Args:
|
27
|
+
# file:: File instance
|
28
|
+
#
|
29
|
+
# Returns true.
|
30
|
+
def write(file)
|
31
|
+
file.truncate 0
|
32
|
+
YAML.dump @data, file
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
# Any future reads / writes will result in a crash.
|
37
|
+
def close
|
38
|
+
@data = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Reads a key from the database.
|
42
|
+
#
|
43
|
+
# Args:
|
44
|
+
# key:: string or symbol
|
45
|
+
#
|
46
|
+
# Returns the value associated with the key, or nil if the key does not exist.
|
47
|
+
def [](key)
|
48
|
+
@data[key.to_s]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Inserts or updates a key in the database.
|
52
|
+
#
|
53
|
+
# Args:
|
54
|
+
# key:: string or symbol
|
55
|
+
# value:: the value to be associated with the key
|
56
|
+
#
|
57
|
+
# Returns value.
|
58
|
+
def []=(key, value)
|
59
|
+
@dirty = true
|
60
|
+
if value.nil?
|
61
|
+
@data.delete key.to_s
|
62
|
+
else
|
63
|
+
@data[key.to_s] = (value.kind_of?(Numeric) || value.kind_of?(Symbol) ||
|
64
|
+
value == true || value == false) ? value : value.dup
|
65
|
+
end
|
66
|
+
value
|
67
|
+
end
|
68
|
+
|
69
|
+
# True if the database contents has changed since the database has been open.
|
70
|
+
def dirty?
|
71
|
+
@dirty
|
72
|
+
end
|
73
|
+
|
74
|
+
# Reads a key from the database, creating a proxy for inexistent keys.
|
75
|
+
#
|
76
|
+
# Args:
|
77
|
+
# key:: string or symbol
|
78
|
+
#
|
79
|
+
# Returns the value associated with the key, or a database access proxy if the
|
80
|
+
# key doesn't exist. This makes it possible to have .-separated keys, like
|
81
|
+
# db.user.name = 'abc'.
|
82
|
+
def proxy_get(key)
|
83
|
+
value = self[key]
|
84
|
+
value.nil? ? Proxy.new(self, key + '.') : value
|
85
|
+
end
|
86
|
+
|
87
|
+
# Inserts or updates
|
88
|
+
#
|
89
|
+
# Args:
|
90
|
+
# key:: string or symbol
|
91
|
+
# value:: the value to be associated with the key
|
92
|
+
#
|
93
|
+
# Returns value.
|
94
|
+
def proxy_set(key, value)
|
95
|
+
self[key] = value
|
96
|
+
end
|
97
|
+
|
98
|
+
if defined? BasicObject
|
99
|
+
# :nodoc: superclass for 1.9+
|
100
|
+
class Proxy < BasicObject; end
|
101
|
+
else
|
102
|
+
# :nodoc: superclass for 1.8
|
103
|
+
class Proxy < Object; end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Easy access to a configuration database.
|
107
|
+
class Proxy
|
108
|
+
def initialize(database, prefix)
|
109
|
+
@db = database
|
110
|
+
@prefix = prefix
|
111
|
+
@eigenclass = (class <<self; self; end)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Proxy objects aren't database values, so they behave like nil.
|
115
|
+
def nil?
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Proxy objects aren't database values, so they behave like nil.
|
120
|
+
def empty?
|
121
|
+
true
|
122
|
+
end
|
123
|
+
|
124
|
+
# Pretty access
|
125
|
+
def method_missing(name, *args)
|
126
|
+
db_key = @prefix + name.to_s
|
127
|
+
do_write = false
|
128
|
+
|
129
|
+
case db_key[-1]
|
130
|
+
when ??
|
131
|
+
db_key = db_key[0...-1]
|
132
|
+
when ?=
|
133
|
+
db_key = db_key[0...-1]
|
134
|
+
do_write = true
|
135
|
+
end
|
136
|
+
|
137
|
+
if do_write
|
138
|
+
@eigenclass.class_eval <<END_DEF
|
139
|
+
def #{name}(value)
|
140
|
+
@db.proxy_set #{db_key.inspect}, value
|
141
|
+
end
|
142
|
+
END_DEF
|
143
|
+
else
|
144
|
+
@eigenclass.class_eval <<END_DEF
|
145
|
+
def #{name}
|
146
|
+
@db.proxy_get #{db_key.inspect}
|
147
|
+
end
|
148
|
+
END_DEF
|
149
|
+
end
|
150
|
+
|
151
|
+
# The method was defined, now fire it off.
|
152
|
+
send name, *args
|
153
|
+
end
|
154
|
+
end # class Pwnbus::ConfigDb::Db::Proxy
|
155
|
+
|
156
|
+
end # class Pwnbus::Configdb::Db
|
157
|
+
|
158
|
+
end # namespace Pwnbus::Configdb
|
159
|
+
|
160
|
+
end # namespace Pwnbus
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
# :nodoc: namespace
|
4
|
+
module Pwnbus
|
5
|
+
|
6
|
+
# :nodoc: file-related functionality
|
7
|
+
module Configdb
|
8
|
+
|
9
|
+
# Handling procedures for database files.
|
10
|
+
module Files
|
11
|
+
# Opens the file for a configuration database. The file must exist.
|
12
|
+
#
|
13
|
+
# Returns a File instance.
|
14
|
+
def self.open_db(db_path, options)
|
15
|
+
db_path = crash_recovery_db_path db_path, options
|
16
|
+
f = File.open db_path, 'r'
|
17
|
+
f.flock options[:read] ? File::LOCK_SH : File::LOCK_EX
|
18
|
+
f
|
19
|
+
end
|
20
|
+
|
21
|
+
# Peforms crash recovery on a database.
|
22
|
+
#
|
23
|
+
# Args:
|
24
|
+
# db_path:: path to a file containing a configuration database
|
25
|
+
# options:: same as for Configdb#new
|
26
|
+
#
|
27
|
+
# Returns the path to the recovered database. Most of the time, this will be
|
28
|
+
def self.crash_recovery_db_path(db_path, options)
|
29
|
+
new_db_path = db_path + '.new'
|
30
|
+
if !File.exist?(db_path)
|
31
|
+
# Crashed during rename.
|
32
|
+
if options[:read]
|
33
|
+
# Writing to the .new copy completed. The copy will be locked.
|
34
|
+
return new_db_path
|
35
|
+
else
|
36
|
+
# Do the rename.
|
37
|
+
File.rename new_db_path, db_path
|
38
|
+
return db_path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if File.exist?(new_db_path) && !options[:read]
|
43
|
+
# Crashed during new version write. The new version is probably corrupted.
|
44
|
+
File.unlink new_db_path
|
45
|
+
end
|
46
|
+
db_path
|
47
|
+
end
|
48
|
+
|
49
|
+
# Writes a new database version atomically.
|
50
|
+
#
|
51
|
+
# Args:
|
52
|
+
# db_path:: path to a file containing a configuration database
|
53
|
+
# options:: same as for Configdb#new
|
54
|
+
#
|
55
|
+
# Returns db_path.
|
56
|
+
def self.write_db(db_path, options)
|
57
|
+
new_db_path = db_path + '.new'
|
58
|
+
File.open(new_db_path, 'w') do |f|
|
59
|
+
f.flock File::LOCK_EX
|
60
|
+
permissions = public_db_name?(File.basename(db_path)) ? 0644 : 0600
|
61
|
+
File.chmod permissions, new_db_path
|
62
|
+
yield f
|
63
|
+
end
|
64
|
+
File.unlink db_path
|
65
|
+
File.rename new_db_path, db_path
|
66
|
+
db_path
|
67
|
+
end
|
68
|
+
|
69
|
+
# True if the file is accessible with the desired Configdb#open options.
|
70
|
+
#
|
71
|
+
# Args:
|
72
|
+
# db_path:: path to a database file
|
73
|
+
# options:: same as for Configdb#new
|
74
|
+
def self.can_access_path?(db_path, options)
|
75
|
+
db_stat = File.stat(db_path)
|
76
|
+
options[:read] ? db_stat.readable? : db_stat.writable?
|
77
|
+
end
|
78
|
+
|
79
|
+
# The path to a database, or nil if the database doesn't exist.
|
80
|
+
#
|
81
|
+
# Args:
|
82
|
+
# name:: the database name
|
83
|
+
def self.find_db(name)
|
84
|
+
db_dir_paths.each do |dir_path|
|
85
|
+
db_path = File.join dir_path, name + '.yml'
|
86
|
+
return db_path if File.exist?(db_path) || File.exist?(db_path + '.new')
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Creates a new database. The database must not exist.
|
92
|
+
#
|
93
|
+
# Args:
|
94
|
+
# name:: the database name
|
95
|
+
# options:: same as for Configdb#open
|
96
|
+
#
|
97
|
+
# Returns the path to the database file.
|
98
|
+
def self.create_db(name, options)
|
99
|
+
db_path = File.join ensure_db_dir_exists, name + '.yml'
|
100
|
+
File.open(db_path, 'w') do |f|
|
101
|
+
f.flock File::LOCK_EX
|
102
|
+
YAML.dump empty_db_data(name), f
|
103
|
+
end
|
104
|
+
permissions = public_db_name?(name) ? 0644 : 0600
|
105
|
+
File.chmod permissions, db_path
|
106
|
+
db_path
|
107
|
+
end
|
108
|
+
|
109
|
+
# The contents of a empty (newly created) database.
|
110
|
+
#
|
111
|
+
# Args:
|
112
|
+
# name:: the database's name
|
113
|
+
def self.empty_db_data(name)
|
114
|
+
{}
|
115
|
+
end
|
116
|
+
|
117
|
+
# Databases whose names start with . are public (global-read, author-write).
|
118
|
+
def self.public_db_name?(name)
|
119
|
+
name[0] != ?.
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the the database directory. Creates it if it doesn't exist.
|
123
|
+
def self.ensure_db_dir_exists
|
124
|
+
dir_path = db_dir_paths.first
|
125
|
+
unless File.exist? dir_path
|
126
|
+
FileUtils.mkdir_p dir_path
|
127
|
+
File.chmod 0755, dir_path
|
128
|
+
end
|
129
|
+
dir_path
|
130
|
+
end
|
131
|
+
|
132
|
+
# Paths to the directory containing database files for the current user.
|
133
|
+
def self.db_dir_paths
|
134
|
+
if superuser?
|
135
|
+
[db_dir_global_path]
|
136
|
+
else
|
137
|
+
[db_dir_user_path, db_dir_global_path]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Path to the directory holding per-user databases.
|
142
|
+
def self.db_dir_user_path
|
143
|
+
File.expand_path('~/.pwnbus')
|
144
|
+
end
|
145
|
+
|
146
|
+
# Path to the computer-global databases.
|
147
|
+
def self.db_dir_global_path
|
148
|
+
'/etc/pwnbus'
|
149
|
+
end
|
150
|
+
|
151
|
+
# True if running as the root user.
|
152
|
+
def self.superuser?
|
153
|
+
Process.euid == 0
|
154
|
+
end
|
155
|
+
end # namespace Pwnbus::Configdb::Files
|
156
|
+
|
157
|
+
end # namespace Pwnbus::Configdb
|
158
|
+
|
159
|
+
end # namespace Pwnbus
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{pwnbus-configdb}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Victor Costan"]
|
12
|
+
s.date = %q{2010-09-19}
|
13
|
+
s.description = %q{Dead-simple key-value store with atomic updates.}
|
14
|
+
s.email = %q{victor@costan.us}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
".project",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/pwnbus/configdb.rb",
|
30
|
+
"lib/pwnbus/configdb/db.rb",
|
31
|
+
"lib/pwnbus/configdb/files.rb",
|
32
|
+
"pwnbus-configdb.gemspec",
|
33
|
+
"spec/.rspec",
|
34
|
+
"spec/db_object_spec.rb",
|
35
|
+
"spec/db_spec.rb",
|
36
|
+
"spec/fixtures/db.yml",
|
37
|
+
"spec/spec_helper.rb"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/pwnall/pwnbus_configdb}
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.7}
|
42
|
+
s.summary = %q{Pure-ruby database for configuration variables.}
|
43
|
+
s.test_files = [
|
44
|
+
"spec/db_object_spec.rb",
|
45
|
+
"spec/db_spec.rb",
|
46
|
+
"spec/spec_helper.rb"
|
47
|
+
]
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
|
+
s.specification_version = 3
|
52
|
+
|
53
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
55
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
56
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
57
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
59
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
61
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
64
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
65
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
66
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
67
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
68
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
69
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
70
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
74
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
75
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
76
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
77
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.20"])
|
78
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
79
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
80
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
data/spec/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Db object" do
|
4
|
+
before do
|
5
|
+
File.open File.expand_path('../fixtures/db.yml', __FILE__) do |f|
|
6
|
+
@db = Pwnbus::Configdb::Db.new f
|
7
|
+
end
|
8
|
+
@proxy = @db.proxy
|
9
|
+
end
|
10
|
+
|
11
|
+
it "reads simple key" do
|
12
|
+
@proxy.variable.should == 'value'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "reads nested key" do
|
16
|
+
@proxy.deeper.variable.should == 'deeper value'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "changes simple key" do
|
20
|
+
@proxy.variable = 'new value'
|
21
|
+
@proxy.variable.should == 'new value'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "changes nested key" do
|
25
|
+
@proxy.deeper.variable = 'new deeper value'
|
26
|
+
@proxy.deeper.variable.should == 'new deeper value'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns nil? object for non-existing keys" do
|
30
|
+
@proxy.none.should be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns nil? object for non-existing nested keys" do
|
34
|
+
@proxy.none.none.should be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "inserts simple key" do
|
38
|
+
@proxy.new_key.should be_nil
|
39
|
+
@proxy.new_key = 'new value'
|
40
|
+
@proxy.new_key.should == 'new value'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "inserts nested key" do
|
44
|
+
@proxy.newer.new_key.should be_nil
|
45
|
+
@proxy.newer.new_key = 'new deep value'
|
46
|
+
@proxy.newer.new_key.should == 'new deep value'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "inserts nested key off existing prefix" do
|
50
|
+
@proxy.deeper.new_key.should be_nil
|
51
|
+
@proxy.deeper.new_key = 'new mixed value'
|
52
|
+
@proxy.deeper.new_key.should == 'new mixed value'
|
53
|
+
end
|
54
|
+
end
|
data/spec/db_spec.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe "Db" do
|
5
|
+
Files = Pwnbus::Configdb::Files
|
6
|
+
Configdb = Pwnbus::Configdb
|
7
|
+
|
8
|
+
shared_examples_for "paths" do
|
9
|
+
it "should have a global path pointing to /etc" do
|
10
|
+
Files.db_dir_paths.last[0, 5].should == '/etc/'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "for non-root user" do
|
15
|
+
it_should_behave_like "paths"
|
16
|
+
|
17
|
+
before do
|
18
|
+
Files.should_receive(:superuser?).and_return(false)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should use a local and a global path" do
|
22
|
+
Files.db_dir_paths.should have(2).items
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "for root user" do
|
27
|
+
before do
|
28
|
+
Files.should_receive(:superuser?).and_return(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should only use the global path" do
|
32
|
+
Files.db_dir_paths.should have(1).item
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Db with stubbed dir" do
|
38
|
+
before do
|
39
|
+
@tempdir = "/tmp/pwnbus-#{(Time.now.to_f * 1000).to_i}"
|
40
|
+
|
41
|
+
@global_dir = File.join @tempdir, 'etc/pwnbus'
|
42
|
+
@user_dir = File.join @tempdir, 'home', 'user', '.pwnbus'
|
43
|
+
Dir.mkdir(@tempdir)
|
44
|
+
Files.stub!(:db_dir_global_path).and_return(@global_dir)
|
45
|
+
Files.stub!(:db_dir_user_path).and_return(@user_dir)
|
46
|
+
end
|
47
|
+
|
48
|
+
after do
|
49
|
+
FileUtils.rm_r(@tempdir)
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "for non-root user" do
|
53
|
+
before do
|
54
|
+
Files.should_receive(:superuser?).at_least(:once).and_return(false)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "saves new databases in the local dir" do
|
58
|
+
Configdb.open('pathtest') { }
|
59
|
+
File.exist?(@global_dir + '/pathtest.yml').should be_false
|
60
|
+
File.exist?(@user_dir + '/pathtest.yml').should be_true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "for root user" do
|
65
|
+
before do
|
66
|
+
Files.should_receive(:superuser?).at_least(:once).and_return(true)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "saves databases in /etc'" do
|
70
|
+
Configdb.open('pathtest') { }
|
71
|
+
File.exist?(@user_dir + '/pathtest.yml').should be_false
|
72
|
+
File.exist?(@global_dir + '/pathtest.yml').should be_true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "with saved db" do
|
77
|
+
before do
|
78
|
+
Configdb.open('persistence') do |c|
|
79
|
+
c.really.long.flag = true
|
80
|
+
c.really.long.number = 41
|
81
|
+
c.really.long.string = 'something'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should report variables correctly" do
|
86
|
+
Configdb.open('persistence') do |c|
|
87
|
+
c.really.long.flag.should == true
|
88
|
+
c.really.long.number.should == 41
|
89
|
+
c.really.long.string.should == 'something'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should make the dbfile world-readable" do
|
94
|
+
(File.stat(@user_dir + '/persistence.yml').mode & 0777).should == 0644
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "after overwriting some vars" do
|
98
|
+
before do
|
99
|
+
Configdb.open('persistence') do |c|
|
100
|
+
c.really.long.number = 42
|
101
|
+
c.really.long.flag = false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should report changes correctly" do
|
106
|
+
Configdb.open('persistence') do |c|
|
107
|
+
c.really.long.flag.should == false
|
108
|
+
c.really.long.number.should == 42
|
109
|
+
c.really.long.string.should == 'something'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "with private db" do
|
116
|
+
before do
|
117
|
+
Configdb.open('.private') do |c|
|
118
|
+
c.secret.pin = '1234'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should not make the dbfile world-readable" do
|
123
|
+
(File.stat(@user_dir + '/.private.yml').mode & 0777).should == 0600
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should be able to read back data" do
|
127
|
+
Configdb.open('.private') { |c| c.secret.pin.should == '1234' }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "after crash" do
|
132
|
+
before do
|
133
|
+
@crash_path = @user_dir + '/crash.yml'
|
134
|
+
@crash_new_path = @crash_path + '.new'
|
135
|
+
FileUtils.mkdir_p @user_dir
|
136
|
+
File.open(@crash_path, 'w') { |f| YAML.dump({'old' => 'yes'}, f) }
|
137
|
+
File.open(@crash_new_path, 'w') { |f| YAML.dump({'old' => 'no'}, f) }
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "during writing" do
|
141
|
+
before do
|
142
|
+
@db_old = Configdb.open('crash') { |crash| crash.old }
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should read the old copy" do
|
146
|
+
@db_old.should == 'yes'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "during rename" do
|
151
|
+
before do
|
152
|
+
File.unlink @crash_path
|
153
|
+
@db_old = Configdb.open('crash') { |crash| crash.old }
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should read the new copy" do
|
157
|
+
@db_old.should == 'no'
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should finish the rename" do
|
161
|
+
File.exist?(@crash_path).should be_true
|
162
|
+
File.exist?(@crash_new_path).should be_false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
10
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
11
|
+
require 'pwnbus/configdb'
|
12
|
+
require 'rspec'
|
13
|
+
|
14
|
+
# Requires supporting files with custom matchers and macros, etc,
|
15
|
+
# in ./support/ and its subdirectories.
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pwnbus-configdb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Victor Costan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-19 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
name: rspec
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 62196427
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- beta
|
35
|
+
- 20
|
36
|
+
version: 2.0.0.beta.20
|
37
|
+
requirement: *id001
|
38
|
+
type: :development
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
prerelease: false
|
41
|
+
name: bundler
|
42
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 23
|
48
|
+
segments:
|
49
|
+
- 1
|
50
|
+
- 0
|
51
|
+
- 0
|
52
|
+
version: 1.0.0
|
53
|
+
requirement: *id002
|
54
|
+
type: :development
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
prerelease: false
|
57
|
+
name: jeweler
|
58
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
hash: -1876988218
|
64
|
+
segments:
|
65
|
+
- 1
|
66
|
+
- 5
|
67
|
+
- 0
|
68
|
+
- pre3
|
69
|
+
version: 1.5.0.pre3
|
70
|
+
requirement: *id003
|
71
|
+
type: :development
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
prerelease: false
|
74
|
+
name: rcov
|
75
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirement: *id004
|
85
|
+
type: :development
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
prerelease: false
|
88
|
+
name: rspec
|
89
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 62196427
|
95
|
+
segments:
|
96
|
+
- 2
|
97
|
+
- 0
|
98
|
+
- 0
|
99
|
+
- beta
|
100
|
+
- 20
|
101
|
+
version: 2.0.0.beta.20
|
102
|
+
requirement: *id005
|
103
|
+
type: :development
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
prerelease: false
|
106
|
+
name: bundler
|
107
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ~>
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
hash: 23
|
113
|
+
segments:
|
114
|
+
- 1
|
115
|
+
- 0
|
116
|
+
- 0
|
117
|
+
version: 1.0.0
|
118
|
+
requirement: *id006
|
119
|
+
type: :development
|
120
|
+
- !ruby/object:Gem::Dependency
|
121
|
+
prerelease: false
|
122
|
+
name: jeweler
|
123
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ~>
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
hash: -1876988218
|
129
|
+
segments:
|
130
|
+
- 1
|
131
|
+
- 5
|
132
|
+
- 0
|
133
|
+
- pre3
|
134
|
+
version: 1.5.0.pre3
|
135
|
+
requirement: *id007
|
136
|
+
type: :development
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
prerelease: false
|
139
|
+
name: rcov
|
140
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
hash: 3
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
version: "0"
|
149
|
+
requirement: *id008
|
150
|
+
type: :development
|
151
|
+
description: Dead-simple key-value store with atomic updates.
|
152
|
+
email: victor@costan.us
|
153
|
+
executables: []
|
154
|
+
|
155
|
+
extensions: []
|
156
|
+
|
157
|
+
extra_rdoc_files:
|
158
|
+
- LICENSE
|
159
|
+
- README.rdoc
|
160
|
+
files:
|
161
|
+
- .document
|
162
|
+
- .gitignore
|
163
|
+
- .project
|
164
|
+
- Gemfile
|
165
|
+
- Gemfile.lock
|
166
|
+
- LICENSE
|
167
|
+
- README.rdoc
|
168
|
+
- Rakefile
|
169
|
+
- VERSION
|
170
|
+
- lib/pwnbus/configdb.rb
|
171
|
+
- lib/pwnbus/configdb/db.rb
|
172
|
+
- lib/pwnbus/configdb/files.rb
|
173
|
+
- pwnbus-configdb.gemspec
|
174
|
+
- spec/.rspec
|
175
|
+
- spec/db_object_spec.rb
|
176
|
+
- spec/db_spec.rb
|
177
|
+
- spec/fixtures/db.yml
|
178
|
+
- spec/spec_helper.rb
|
179
|
+
has_rdoc: true
|
180
|
+
homepage: http://github.com/pwnall/pwnbus_configdb
|
181
|
+
licenses: []
|
182
|
+
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
|
186
|
+
require_paths:
|
187
|
+
- lib
|
188
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
189
|
+
none: false
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
hash: 3
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
version: "0"
|
197
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
|
+
none: false
|
199
|
+
requirements:
|
200
|
+
- - ">="
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
hash: 3
|
203
|
+
segments:
|
204
|
+
- 0
|
205
|
+
version: "0"
|
206
|
+
requirements: []
|
207
|
+
|
208
|
+
rubyforge_project:
|
209
|
+
rubygems_version: 1.3.7
|
210
|
+
signing_key:
|
211
|
+
specification_version: 3
|
212
|
+
summary: Pure-ruby database for configuration variables.
|
213
|
+
test_files:
|
214
|
+
- spec/db_object_spec.rb
|
215
|
+
- spec/db_spec.rb
|
216
|
+
- spec/spec_helper.rb
|