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.
@@ -0,0 +1,8 @@
1
+ === 0.0.1 / 2008-08-11
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday; project created
6
+ * Standard secretary, error, and YAML gopher classes created
7
+ * Secretary, error, and YAML gopher RSpec specifications created
8
+
@@ -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
@@ -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.
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ ---
2
+ - Foo
3
+ - Bar
4
+ - Bam
@@ -0,0 +1,5 @@
1
+ This is an invalid preferences file for use in unit tests and specs. The
2
+ following lines are meant to be invalid YAML syntax.
3
+
4
+ foo bar: bash
5
+ [32, 23, 53]
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ ---
2
+ name: Billy Bob
3
+ email: xxx@yyy.zzz
@@ -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
@@ -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
+