secretary 0.0.1
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/History.txt +8 -0
- data/Manifest.txt +15 -0
- data/README.txt +92 -0
- data/Rakefile +12 -0
- data/lib/secretary.rb +57 -0
- data/lib/secretary/error.rb +31 -0
- data/lib/secretary/gopher.rb +59 -0
- data/lib/secretary/gopher/yaml.rb +27 -0
- data/spec/array.yaml +4 -0
- data/spec/broken-yaml.txt +5 -0
- data/spec/error_spec.rb +30 -0
- data/spec/gopher_spec.rb +157 -0
- data/spec/hash.yaml +3 -0
- data/spec/secretary_spec.rb +259 -0
- data/spec/spec_helper.rb +1 -0
- metadata +81 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
lib/secretary.rb
|
6
|
+
lib/secretary/error.rb
|
7
|
+
lib/secretary/gopher.rb
|
8
|
+
lib/secretary/gopher/yaml.rb
|
9
|
+
spec/spec_helper.rb
|
10
|
+
spec/secretary_spec.rb
|
11
|
+
spec/error_spec.rb
|
12
|
+
spec/gopher_spec.rb
|
13
|
+
spec/hash.yaml
|
14
|
+
spec/array.yaml
|
15
|
+
spec/broken-yaml.txt
|
data/README.txt
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= secretary
|
2
|
+
|
3
|
+
* http://secretary.rubyforge.org
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Secretary is a gem who makes managing simple preference files in Ruby easy
|
8
|
+
and painless. If you tire of being bound to PStore or YAML and want a
|
9
|
+
consistent, pluggable way to read and write preferences, your Secretary would
|
10
|
+
be happy to help!
|
11
|
+
|
12
|
+
== FEATURES:
|
13
|
+
|
14
|
+
* She's smooth and simple: just import and initialize!
|
15
|
+
* She flexible: though she uses the simple YAML markup language by default, she
|
16
|
+
can easily switch to any other format!
|
17
|
+
* She supports custom defaults, a big essential!
|
18
|
+
* She's easily extensible--subclass Secretary::Gopher to be able to load any
|
19
|
+
kind of file you wish!
|
20
|
+
* All in all, she's a small, no-frills object who gives you one less thing to
|
21
|
+
worry about. It can't be any easier!
|
22
|
+
|
23
|
+
== SYNOPSIS:
|
24
|
+
|
25
|
+
import 'secretary/simple'
|
26
|
+
|
27
|
+
preferences = {'name': 'Samantha', 'port': 151}
|
28
|
+
defaults = {'name': '', 'port': 80}
|
29
|
+
|
30
|
+
secretary = Secretary.new 'preferences.yaml', defaults
|
31
|
+
|
32
|
+
# The first argument is the path to the file that she will sync to.
|
33
|
+
# The second argument indicates the object that contains her defaults.
|
34
|
+
# There's also an optional third argument that determines how she will sync
|
35
|
+
# with her file--by default, it'll be YAML.
|
36
|
+
|
37
|
+
secretary['url'] = 'http://samantha.name'
|
38
|
+
|
39
|
+
secretary['name'] # <- 'Samantha'
|
40
|
+
secretary['url'] = 'http://samantha.name'
|
41
|
+
secretary['port'] # <- 80
|
42
|
+
|
43
|
+
secretary.save # Saves to a YAML file called 'preferences.yaml'.
|
44
|
+
|
45
|
+
== REQUIREMENTS:
|
46
|
+
|
47
|
+
* At least Ruby 1.8.0
|
48
|
+
* The standard forwarable.rb
|
49
|
+
* The standard yaml.rb
|
50
|
+
* At least RSpec 1.1 (but only if you want to unit test using Secretary's
|
51
|
+
included specs)
|
52
|
+
|
53
|
+
== INSTALL:
|
54
|
+
|
55
|
+
The recommended way to install Secretary is to use rubygems to download and
|
56
|
+
install it automatically:
|
57
|
+
|
58
|
+
gem install secretary
|
59
|
+
|
60
|
+
== NOTES:
|
61
|
+
|
62
|
+
I'm planning to add support for managing arbitrary objects, not just Hashes,
|
63
|
+
as well as support for more formats like CSV (easy), JSON (easier), and XML
|
64
|
+
(hard).
|
65
|
+
|
66
|
+
In addition, this is my first programming project ever, and I'm sort of not
|
67
|
+
used to this. I'd be very happy to hear your comments and bugs on Rubyforge.
|
68
|
+
|
69
|
+
== LICENSE:
|
70
|
+
|
71
|
+
(The MIT License)
|
72
|
+
|
73
|
+
Copyright (c) 2008
|
74
|
+
|
75
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
76
|
+
a copy of this software and associated documentation files (the
|
77
|
+
'Software'), to deal in the Software without restriction, including
|
78
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
79
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
80
|
+
permit persons to whom the Software is furnished to do so, subject to
|
81
|
+
the following conditions:
|
82
|
+
|
83
|
+
The above copyright notice and this permission notice shall be
|
84
|
+
included in all copies or substantial portions of the Software.
|
85
|
+
|
86
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
87
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
88
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
89
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
90
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
91
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
92
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/secretary'
|
6
|
+
|
7
|
+
Hoe.new('secretary', Secretary::VERSION) do |p|
|
8
|
+
p.developer('Joshua Choi', 'joshua@choi.name')
|
9
|
+
p.remote_rdoc_dir = '' # Release to root
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=Ruby
|
data/lib/secretary.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
require 'secretary/error'
|
3
|
+
require 'secretary/gopher/yaml'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
class Secretary
|
7
|
+
VERSION = '0.0.1'
|
8
|
+
extend Forwardable
|
9
|
+
include Enumerable
|
10
|
+
attr_reader :file_path, :defaults, :gopher
|
11
|
+
|
12
|
+
def initialize(file_path, defaults={}, gopher_class=Gopher::YAML)
|
13
|
+
unless gopher_class.respond_to? :new
|
14
|
+
raise ArgumentError, "given gopher class is not a class (#{gopher_class})"
|
15
|
+
end
|
16
|
+
@file_path = file_path
|
17
|
+
@defaults = defaults
|
18
|
+
@gopher = gopher_class.new Hash
|
19
|
+
unless @gopher.respond_to? :load_from_path
|
20
|
+
raise ArgumentError, "given gopher class\'s members do not respond to :load_from_path (#{gopher})"
|
21
|
+
end
|
22
|
+
@contents = {}
|
23
|
+
reload
|
24
|
+
end
|
25
|
+
|
26
|
+
def_delegators :to_hash, :[], :include?, :each, :each_pair, :each_key, :each_value
|
27
|
+
def_delegators :@contents, :[]=, :delete
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
other.respond_to? :file_path and other.respond_to? :defaults \
|
31
|
+
and other.respond_to? :gopher and other.respond_to? :to_hash \
|
32
|
+
and file_path == other.file_path and defaults == other.defaults \
|
33
|
+
and gopher == other.gopher and to_hash == other.to_hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash
|
37
|
+
defaults.merge @contents
|
38
|
+
end
|
39
|
+
|
40
|
+
def reload
|
41
|
+
begin
|
42
|
+
loaded_data = gopher.load_from_path(file_path)
|
43
|
+
unless loaded_data.respond_to? :to_hash
|
44
|
+
raise IOError, "gopher's loaded data is unconvertable to a Hash and thus invalid (#{loaded_data})"
|
45
|
+
end
|
46
|
+
@contents.merge! loaded_data
|
47
|
+
return true
|
48
|
+
rescue Error::MissingFile
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def save
|
54
|
+
gopher.save self.to_hash, file_path
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Secretary
|
2
|
+
|
3
|
+
module Error
|
4
|
+
|
5
|
+
class MissingFile < IOError
|
6
|
+
|
7
|
+
def initialize(missing_file_path)
|
8
|
+
super "no such file or directory (#{missing_file_path})"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class Parsing < IOError
|
14
|
+
|
15
|
+
def initialize(parsing_error, file_type)
|
16
|
+
super "attempted to parse an invalid #{file_type} file (#{parsing_error})"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class InvalidData < IOError
|
22
|
+
|
23
|
+
def initialize(data, valid_data_type)
|
24
|
+
super "preference file of invalid data type (should be #{valid_data_type} instead of #{data.class})"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'secretary/error'
|
2
|
+
|
3
|
+
class Secretary
|
4
|
+
|
5
|
+
class Gopher
|
6
|
+
# Abstract base class that requires methods #parse_file(input_file),
|
7
|
+
# #valid_file_type(), and #emit(data) to survive.
|
8
|
+
VERSION = '0.0.1'
|
9
|
+
attr_reader :valid_data_type
|
10
|
+
class << self
|
11
|
+
attr_reader :valid_file_type
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(valid_data_type)
|
15
|
+
@valid_data_type = valid_data_type
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_from_path(file_path)
|
19
|
+
if File.exist? file_path
|
20
|
+
open file_path do |file|
|
21
|
+
return load_from_file(file)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise Secretary::Error::MissingFile.new(file_path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_from_file(file)
|
29
|
+
begin
|
30
|
+
file_data = parse_file file
|
31
|
+
rescue Secretary::Error::Parsing => parsing_error
|
32
|
+
raise parsing_error
|
33
|
+
end
|
34
|
+
unless file_data.kind_of? valid_data_type
|
35
|
+
raise Secretary::Error::InvalidData.new(file_data, valid_data_type)
|
36
|
+
end
|
37
|
+
return file_data
|
38
|
+
end
|
39
|
+
|
40
|
+
def save(data, file_path)
|
41
|
+
unless data.kind_of? valid_data_type
|
42
|
+
raise ArgumentError, "invalid data #{data} is not a kind of #{valid_data_type}"
|
43
|
+
end
|
44
|
+
open file_path, 'w' do |file|
|
45
|
+
file.puts emit(data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def valid_file_type
|
50
|
+
self.class.valid_file_type
|
51
|
+
end
|
52
|
+
|
53
|
+
def ==(other)
|
54
|
+
self.class == other.class
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'secretary/gopher'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class Secretary
|
5
|
+
|
6
|
+
class Gopher
|
7
|
+
|
8
|
+
class YAML < Secretary::Gopher
|
9
|
+
@valid_file_type = 'YAML'
|
10
|
+
|
11
|
+
def parse_file(file)
|
12
|
+
begin
|
13
|
+
return ::YAML::load(file)
|
14
|
+
rescue ArgumentError => parsing_error
|
15
|
+
raise Secretary::Error::Parsing.new(parsing_error, valid_file_type)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def emit(data)
|
20
|
+
data.to_yaml
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/spec/array.yaml
ADDED
data/spec/error_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'lib/secretary'
|
3
|
+
|
4
|
+
describe Secretary::Error::MissingFile do
|
5
|
+
|
6
|
+
it 'should have a message with the missing file\'s path' do
|
7
|
+
Secretary::Error::MissingFile.new('missing-file.txt').to_s \
|
8
|
+
.should == 'no such file or directory (missing-file.txt)'
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Secretary::Error::Parsing do
|
14
|
+
|
15
|
+
it 'should have a message with the missing file\'s path' do
|
16
|
+
parsing_error = SyntaxError.new 'invalid char found at line 3'
|
17
|
+
Secretary::Error::Parsing.new(parsing_error, 'YAML').to_s \
|
18
|
+
.should == 'attempted to parse an invalid YAML file (invalid char found at line 3)'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Secretary::Error::InvalidData do
|
24
|
+
|
25
|
+
it 'should have a message with the missing file\'s path' do
|
26
|
+
Secretary::Error::InvalidData.new([3, 2], Hash).to_s \
|
27
|
+
.should == 'preference file of invalid data type (should be Hash instead of Array)'
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/spec/gopher_spec.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'lib/secretary/gopher/yaml'
|
3
|
+
|
4
|
+
describe Secretary::Gopher::YAML do
|
5
|
+
|
6
|
+
it 'should be equal with another if they are of equal class' do
|
7
|
+
gopher0 = Secretary::Gopher::YAML.new stub_everything
|
8
|
+
gopher1 = Secretary::Gopher::YAML.new stub_everything
|
9
|
+
gopher0.should == gopher1
|
10
|
+
gopher1.should == gopher0
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be unequal with another if they are of unequal class, even if the other is a kind of its class' do
|
14
|
+
gopher0 = Secretary::Gopher::YAML.new stub_everything
|
15
|
+
gopher1 = stub :kind_of? => true
|
16
|
+
gopher0.should_not == gopher1
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
it 'should know its valid data type' do
|
21
|
+
data_type = stub 'Data Type'
|
22
|
+
gopher = Secretary::Gopher::YAML.new data_type
|
23
|
+
gopher.valid_data_type.should == data_type
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should know its valid file type and it should be YAML' do
|
27
|
+
Secretary::Gopher::YAML.new(stub_everything).valid_file_type.should == 'YAML'
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'when trying to save an object into a YAML file using a file path' do
|
31
|
+
|
32
|
+
it 'should save a given Hash when the valid data type is Hash' do
|
33
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
34
|
+
data = {:name => 'Tracy', :url => 'http://tracy.name'}
|
35
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
36
|
+
gopher.save data, file_path
|
37
|
+
open file_path do |file|
|
38
|
+
YAML::load(file).should == data
|
39
|
+
end
|
40
|
+
File.delete file_path
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should save a given object when the object is of its valid data type' do
|
44
|
+
class Person
|
45
|
+
def initialize
|
46
|
+
@name = 'Sal'
|
47
|
+
@age = 76
|
48
|
+
end
|
49
|
+
def ==(other)
|
50
|
+
self.class == other.class
|
51
|
+
end
|
52
|
+
end
|
53
|
+
data = Person.new
|
54
|
+
gopher = Secretary::Gopher::YAML.new Person
|
55
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
56
|
+
gopher.save data, file_path
|
57
|
+
open file_path do |file|
|
58
|
+
YAML::load(file).should == data
|
59
|
+
end
|
60
|
+
File.delete file_path
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should raise an error if it tries to save data that is not of its valid data type' do
|
64
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
65
|
+
data = [3, 2, 1]
|
66
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
67
|
+
lambda { gopher.save data, file_path }.should raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should not create a new file if it tries to save data that is not of its valid data type' do
|
71
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
72
|
+
data = [3, 2, 1]
|
73
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
74
|
+
begin
|
75
|
+
gopher.save data, file_path
|
76
|
+
rescue ArgumentError
|
77
|
+
end
|
78
|
+
File.exists?(file_path).should_not be_true
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should not modify any file if it tries to save data that is not of its valid data type' do
|
82
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
83
|
+
data0 = {:name => 'Tracy', :url => 'http://tracy.name'}
|
84
|
+
data1 = [3, 2, 1]
|
85
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
86
|
+
gopher.save data0, file_path
|
87
|
+
begin
|
88
|
+
gopher.save data1, file_path
|
89
|
+
rescue ArgumentError
|
90
|
+
end
|
91
|
+
open file_path do |file|
|
92
|
+
YAML::load(file).should == data0
|
93
|
+
end
|
94
|
+
File.delete file_path
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'when reading from a file' do
|
100
|
+
|
101
|
+
it 'should get the file\'s data when the file is YAML and that data is a Hash and the given type is Hash' do
|
102
|
+
preferences0 = {'name' => 'Billy Bob', 'email' => 'xxx@yyy.zzz'}
|
103
|
+
file_path = File.dirname(__FILE__) + '/hash.yaml'
|
104
|
+
open file_path do |file|
|
105
|
+
require 'yaml'
|
106
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
107
|
+
preferences1 = gopher.load_from_file file
|
108
|
+
preferences1.should == preferences0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should raise a ParsingError when the file is not YAML' do
|
113
|
+
gopher = Secretary::Gopher::YAML.new stub_everything
|
114
|
+
file_path = File.dirname(__FILE__) + '/broken-yaml.txt'
|
115
|
+
open file_path do |file|
|
116
|
+
lambda { gopher.load_from_file file } \
|
117
|
+
.should raise_error(Secretary::Error::Parsing)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should raise an InvalidDataError when the file\'s data is not a Hash and the valid data type is Hash' do
|
122
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
123
|
+
file_path = File.dirname(__FILE__) + '/array.yaml'
|
124
|
+
open file_path do |file|
|
125
|
+
lambda { gopher.load_from_file file } \
|
126
|
+
.should raise_error(Secretary::Error::InvalidData)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
describe 'when reading from a path to a file' do
|
133
|
+
|
134
|
+
it 'should raise a MissingFileError when the path leads to nowhere' do
|
135
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
136
|
+
lambda { gopher.load_from_path 'missing-file.yaml' } \
|
137
|
+
.should raise_error(Secretary::Error::MissingFile)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should get the path\'s file\'s data when the file is YAML and that data is a Hash and the given type is Hash' do
|
141
|
+
preferences0 = {'name' => 'Billy Bob', 'email' => 'xxx@yyy.zzz'}
|
142
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
143
|
+
file_path = File.dirname(__FILE__) + '/hash.yaml'
|
144
|
+
preferences1 = gopher.load_from_path(file_path)
|
145
|
+
preferences1.should == preferences0
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should raise an InvalidDataError when the path\'s file\'s data is not a Hash and the valid data type is Hash' do
|
149
|
+
gopher = Secretary::Gopher::YAML.new Hash
|
150
|
+
file_path = File.dirname(__FILE__) + '/array.yaml'
|
151
|
+
lambda { gopher.load_from_path file_path } \
|
152
|
+
.should raise_error(Secretary::Error::InvalidData)
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
data/spec/hash.yaml
ADDED
@@ -0,0 +1,259 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'lib/secretary'
|
3
|
+
require 'lib/secretary/gopher/yaml'
|
4
|
+
|
5
|
+
describe Secretary do
|
6
|
+
|
7
|
+
it 'should be enumerable' do
|
8
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
9
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
10
|
+
file_path = stub 'File Path'
|
11
|
+
secretary = Secretary.new file_path, {}, gopher_class
|
12
|
+
secretary.should be_a_kind_of(Enumerable)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should know the file path it saves to' do
|
16
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
17
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
18
|
+
file_path = stub 'File Path'
|
19
|
+
secretary = Secretary.new file_path, {}, gopher_class
|
20
|
+
secretary.file_path.should == file_path
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should know its defaults' do
|
24
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
25
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
26
|
+
secretary = Secretary.new stub_everything, {'name' => ''}, gopher_class
|
27
|
+
secretary.defaults.should == {'name' => ''}
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should have an empty hash for its defaults by default' do
|
31
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
32
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
33
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
34
|
+
secretary.defaults.should == {}
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should create a new gopher, which expects a Hash, from the given gopher class' do
|
38
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
39
|
+
gopher_class = mock 'Gopher Class'
|
40
|
+
gopher_class.should_receive(:new).with(Hash).and_return(gopher)
|
41
|
+
secretary = Secretary.new stub_everything, stub_everything, gopher_class
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should create a new YAML gopher by default' do
|
45
|
+
secretary = Secretary.new 'file_path'
|
46
|
+
secretary.gopher.should be_a_kind_of(Secretary::Gopher::YAML)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should know its gopher' do
|
50
|
+
defaults = stub_everything
|
51
|
+
gopher = stub 'Gopher', :load_from_path => {}
|
52
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
53
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should be able to set its values' do
|
57
|
+
data = {'name' => 'Billy Bob'}
|
58
|
+
gopher = stub 'Gopher', :load_from_path => data
|
59
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
60
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
61
|
+
secretary['name'] = 'Joe'
|
62
|
+
secretary['name'].should == 'Joe'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should be able to delete its values' do
|
66
|
+
data = {'name' => 'Billy Bob'}
|
67
|
+
gopher = stub 'Gopher', :load_from_path => data
|
68
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
69
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
70
|
+
secretary.delete 'name'
|
71
|
+
secretary.should_not include('name')
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'when accessing a key' do
|
75
|
+
|
76
|
+
it 'should know the key\'s value' do
|
77
|
+
data = {'name' => 'Billy Bob'}
|
78
|
+
gopher = stub 'Gopher', :load_from_path => data
|
79
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
80
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
81
|
+
secretary['name'].should == 'Billy Bob'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should give the key\'s corresponding default value if the key\'s does not otherwise exist in its contents' do
|
85
|
+
defaults = {'name' => 'Billy Bob'}
|
86
|
+
data = {}
|
87
|
+
gopher = stub 'Gopher', :load_from_path => data
|
88
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
89
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
90
|
+
secretary['name'].should == 'Billy Bob'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should give the key\'s corresponding default value after the key is deleted' do
|
94
|
+
defaults = {'name' => 'Joe'}
|
95
|
+
data = {'name' => 'Billy Bob'}
|
96
|
+
gopher = stub 'Gopher', :load_from_path => data
|
97
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
98
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
99
|
+
secretary.delete 'name'
|
100
|
+
secretary['name'].should == 'Joe'
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'using a custom gopher' do
|
106
|
+
|
107
|
+
it 'should raise an error when its given gopher class cannot make new gophers' do
|
108
|
+
gopher_class = stub 'Gopher Class'
|
109
|
+
lambda { Secretary.new stub_everything, {}, gopher_class } \
|
110
|
+
.should raise_error(ArgumentError)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should raise an error when its given gopher class\'s objects cannot act like gophers' do
|
114
|
+
gopher = stub 'Gopher'
|
115
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
116
|
+
lambda { Secretary.new stub_everything, {}, gopher_class } \
|
117
|
+
.should raise_error(ArgumentError)
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'updating itself based on what the gopher brings from its file path' do
|
121
|
+
|
122
|
+
it 'have contents of its defaults merged with the file\'s data, when initialized' do
|
123
|
+
defaults = {:bash => 'bang', :bar => 'bing'}
|
124
|
+
data = {:bar => 'foo', :bam => 'fiz'}
|
125
|
+
gopher = stub 'Gopher', :load_from_path => data
|
126
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
127
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
128
|
+
secretary.to_hash.should == defaults.merge(data)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'have contents of its defaults only if its file does not yet exist, when initialized' do
|
132
|
+
defaults = {:bash => 'bang', :bar => 'bing'}
|
133
|
+
gopher = stub 'Gopher'
|
134
|
+
gopher.stub!(:load_from_path).and_raise(
|
135
|
+
Secretary::Error::MissingFile.new(stub_everything)
|
136
|
+
)
|
137
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
138
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
139
|
+
secretary.to_hash.should == defaults
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should update its contents with its defaults, based on what the gopher brings from its file path, when reloaded' do
|
143
|
+
defaults = {:bash => 'bang', :bar => 'bing'}
|
144
|
+
data = {:bar => 'foo', :bam => 'fiz'}
|
145
|
+
gopher = stub 'Gopher'
|
146
|
+
gopher.stub!(:load_from_path).and_return({}, data)
|
147
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
148
|
+
secretary = Secretary.new stub_everything, defaults, gopher_class
|
149
|
+
secretary.reload
|
150
|
+
secretary.to_hash.should == defaults.merge(data)
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should send its contents to the gopher when saving' do
|
156
|
+
contents = {:bar => 'foo', :bam => 'fiz'}
|
157
|
+
file_path = stub_everything
|
158
|
+
gopher = stub 'Gopher', :load_from_path => contents
|
159
|
+
gopher.should_receive(:save).with(contents, file_path).once
|
160
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
161
|
+
secretary = Secretary.new file_path, {}, gopher_class
|
162
|
+
secretary.save
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'using a default YAML gopher' do
|
168
|
+
|
169
|
+
describe 'updating itself based on what the gopher brings from its file path' do
|
170
|
+
|
171
|
+
it 'have contents of its defaults merged with the file\'s data, when initialized' do
|
172
|
+
defaults = {'name' => '', 'port' => 80}
|
173
|
+
data = {'name' => 'Billy Bob', 'email' => 'xxx@yyy.zzz'}
|
174
|
+
file_path = File.dirname(__FILE__) + '/hash.yaml'
|
175
|
+
secretary = Secretary.new file_path, defaults
|
176
|
+
secretary.to_hash.should == defaults.merge(data)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'have contents of its defaults only if its file does not yet exist, when initialized' do
|
180
|
+
defaults = {'name' => '', 'port' => 80}
|
181
|
+
file_path = File.dirname(__FILE__) + '/missing_file.yaml'
|
182
|
+
secretary = Secretary.new file_path, defaults
|
183
|
+
secretary.to_hash.should == defaults
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'when saving data' do
|
189
|
+
|
190
|
+
it 'should create a new data file if it does not exist' do
|
191
|
+
defaults = {'name' => '', 'port' => 80}
|
192
|
+
data = {'name' => 'Billy Bob', 'email' => 'xxx@yyy.zzz'}
|
193
|
+
file_path = File.dirname(__FILE__) + '/temporary.yaml'
|
194
|
+
secretary = Secretary.new file_path, defaults
|
195
|
+
secretary.save
|
196
|
+
File.exists?(file_path).should be_true
|
197
|
+
File.delete file_path
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'when comparing with another object' do
|
205
|
+
|
206
|
+
it 'should be equal if their file paths, defaults, and contents are equal' do
|
207
|
+
file_path = stub_everything
|
208
|
+
defaults = {:boo => 'bash'}
|
209
|
+
contents = {:boo => 'bam', :foo => 'bar'}
|
210
|
+
gopher = stub 'Gopher', :load_from_path => contents
|
211
|
+
gopher_class = stub 'Gopher Class', :new => gopher
|
212
|
+
secretary = Secretary.new file_path, defaults, gopher_class
|
213
|
+
other = stub 'Other', :file_path => file_path, :defaults => defaults,
|
214
|
+
:gopher => gopher, :to_hash => contents
|
215
|
+
secretary.to_hash.should == other.to_hash
|
216
|
+
secretary.should == other
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should be unequal if their file paths are unequal' do
|
220
|
+
defaults = {:bash => 'bang', :bar => 'bing'}
|
221
|
+
gopher_class = stub 'Gopher Class', :new => stub('Gopher', :load_from_path => {})
|
222
|
+
secretary0 = Secretary.new stub_everything, defaults, gopher_class
|
223
|
+
secretary1 = Secretary.new stub_everything, defaults, gopher_class
|
224
|
+
secretary0.should_not == secretary1
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should be unequal if their defaults are unequal' do
|
228
|
+
gopher_class = stub 'Gopher Class', :new => stub('Gopher', :load_from_path => {})
|
229
|
+
defaults0 = {:bash => 'bang', :bar => 'bing'}
|
230
|
+
defaults1 = {:bash => 'foo', :bar => 'bing'}
|
231
|
+
secretary0 = Secretary.new stub_everything, defaults0, gopher_class
|
232
|
+
secretary1 = Secretary.new stub_everything, defaults1, gopher_class
|
233
|
+
secretary0.should_not == secretary1
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should be unequal if the other does not respond to :file_path' do
|
237
|
+
gopher_class = stub 'Gopher Class', :new => stub('Gopher', :load_from_path => {})
|
238
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
239
|
+
other = stub 'Other'
|
240
|
+
secretary.should_not == other
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should be unequal if the other does not respond to :gopher' do
|
244
|
+
gopher_class = stub 'Gopher Class', :new => stub('Gopher', :load_from_path => {})
|
245
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
246
|
+
other = stub 'Other'
|
247
|
+
secretary.should_not == other
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'should be unequal if the other does not respond to :file_path' do
|
251
|
+
gopher_class = stub 'Gopher Class', :new => stub('Gopher', :load_from_path => {})
|
252
|
+
secretary = Secretary.new stub_everything, {}, gopher_class
|
253
|
+
other = stub 'Other'
|
254
|
+
secretary.should_not == other
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: secretary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Choi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.0
|
24
|
+
version:
|
25
|
+
description: Secretary is a gem who makes managing simple preference files in Ruby easy and painless. If you tire of being bound to PStore or YAML and want a consistent, pluggable way to read and write preferences, your Secretary would be happy to help!
|
26
|
+
email:
|
27
|
+
- joshua@choi.name
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
- spec/broken-yaml.txt
|
37
|
+
files:
|
38
|
+
- History.txt
|
39
|
+
- Manifest.txt
|
40
|
+
- README.txt
|
41
|
+
- Rakefile
|
42
|
+
- lib/secretary.rb
|
43
|
+
- lib/secretary/error.rb
|
44
|
+
- lib/secretary/gopher.rb
|
45
|
+
- lib/secretary/gopher/yaml.rb
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- spec/secretary_spec.rb
|
48
|
+
- spec/error_spec.rb
|
49
|
+
- spec/gopher_spec.rb
|
50
|
+
- spec/hash.yaml
|
51
|
+
- spec/array.yaml
|
52
|
+
- spec/broken-yaml.txt
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://secretary.rubyforge.org
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --main
|
58
|
+
- README.txt
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project: secretary
|
76
|
+
rubygems_version: 1.2.0
|
77
|
+
signing_key:
|
78
|
+
specification_version: 2
|
79
|
+
summary: Secretary is a gem who makes managing simple preference files in Ruby easy and painless
|
80
|
+
test_files: []
|
81
|
+
|