hiera 2.0.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +202 -0
  3. data/LICENSE +18 -0
  4. data/README.md +276 -0
  5. data/bin/hiera +248 -0
  6. data/lib/hiera/backend/json_backend.rb +58 -0
  7. data/lib/hiera/backend/yaml_backend.rb +63 -0
  8. data/lib/hiera/backend.rb +325 -0
  9. data/lib/hiera/config.rb +90 -0
  10. data/lib/hiera/console_logger.rb +13 -0
  11. data/lib/hiera/error.rb +4 -0
  12. data/lib/hiera/fallback_logger.rb +41 -0
  13. data/lib/hiera/filecache.rb +86 -0
  14. data/lib/hiera/interpolate.rb +98 -0
  15. data/lib/hiera/noop_logger.rb +8 -0
  16. data/lib/hiera/puppet_logger.rb +17 -0
  17. data/lib/hiera/recursive_guard.rb +20 -0
  18. data/lib/hiera/util.rb +47 -0
  19. data/lib/hiera/version.rb +89 -0
  20. data/lib/hiera.rb +115 -0
  21. data/spec/spec_helper.rb +78 -0
  22. data/spec/unit/backend/json_backend_spec.rb +85 -0
  23. data/spec/unit/backend/yaml_backend_spec.rb +138 -0
  24. data/spec/unit/backend_spec.rb +743 -0
  25. data/spec/unit/config_spec.rb +118 -0
  26. data/spec/unit/console_logger_spec.rb +19 -0
  27. data/spec/unit/fallback_logger_spec.rb +80 -0
  28. data/spec/unit/filecache_spec.rb +142 -0
  29. data/spec/unit/fixtures/interpolate/config/hiera.yaml +6 -0
  30. data/spec/unit/fixtures/interpolate/data/niltest.yaml +2 -0
  31. data/spec/unit/fixtures/interpolate/data/recursive.yaml +3 -0
  32. data/spec/unit/fixtures/override/config/hiera.yaml +5 -0
  33. data/spec/unit/fixtures/override/data/alternate.yaml +1 -0
  34. data/spec/unit/fixtures/override/data/common.yaml +2 -0
  35. data/spec/unit/hiera_spec.rb +81 -0
  36. data/spec/unit/interpolate_spec.rb +36 -0
  37. data/spec/unit/puppet_logger_spec.rb +31 -0
  38. data/spec/unit/util_spec.rb +49 -0
  39. data/spec/unit/version_spec.rb +44 -0
  40. metadata +128 -0
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ class Hiera
4
+ describe Config do
5
+ describe "#load" do
6
+ let(:default_config) do
7
+ {
8
+ :backends => ["yaml"],
9
+ :hierarchy => "common",
10
+ :logger => "console",
11
+ :merge_behavior=>:native
12
+ }
13
+ end
14
+
15
+ it "should treat string sources as a filename" do
16
+ expect { Config.load("/nonexisting") }.to raise_error
17
+ end
18
+
19
+ it "should raise an error for missing config files" do
20
+ File.expects(:exist?).with("/nonexisting").returns(false)
21
+ YAML.expects(:load_file).with("/nonexisting").never
22
+
23
+ expect { Config.load("/nonexisting") }.to raise_error "Config file /nonexisting not found"
24
+ end
25
+
26
+ it "should attempt to YAML load config files" do
27
+ File.expects(:exist?).with("/nonexisting").returns(true)
28
+ YAML.expects(:load_file).with("/nonexisting").returns(YAML.load("---\n"))
29
+
30
+ Config.load("/nonexisting")
31
+ end
32
+
33
+ it "should use defaults on empty YAML config file" do
34
+ File.expects(:exist?).with("/nonexisting").returns(true)
35
+ YAML.expects(:load_file).with("/nonexisting").returns(YAML.load(""))
36
+
37
+ Config.load("/nonexisting").should == default_config
38
+ end
39
+
40
+ it "should use hash data as source if supplied" do
41
+ config = Config.load({"rspec" => "test"})
42
+ config["rspec"].should == "test"
43
+ end
44
+
45
+ it "should merge defaults with the loaded or supplied config" do
46
+ config = Config.load({})
47
+ config.should == {:backends => ["yaml"], :hierarchy => "common", :logger => "console", :merge_behavior=>:native}
48
+ end
49
+
50
+ it "should force :backends to be a flattened array" do
51
+ Config.load({:backends => [["foo", ["bar"]]]}).should == {:backends => ["foo", "bar"], :hierarchy => "common", :logger => "console", :merge_behavior=>:native}
52
+ end
53
+
54
+ it "should load the supplied logger" do
55
+ Hiera.expects(:logger=).with("foo")
56
+ Config.load({:logger => "foo"})
57
+ end
58
+
59
+ it "should default to the console logger" do
60
+ Hiera.expects(:logger=).with("console")
61
+ Config.load({})
62
+ end
63
+
64
+ context "loading '/dev/null' as spec tests do", :unless => Hiera::Util.microsoft_windows? do
65
+ before :each do
66
+ # Simulate the behavior of YAML.load_file('/dev/null') in MRI 1.9.3p194
67
+ Config.stubs(:yaml_load_file).
68
+ raises(TypeError, "no implicit conversion from nil to integer")
69
+ end
70
+
71
+ it "is not exceptional behavior" do
72
+ Config.load('/dev/null')
73
+ end
74
+ end
75
+
76
+ describe "if deep_merge can't be loaded" do
77
+ let(:error_message) { "Must have 'deep_merge' gem installed for the configured merge_behavior." }
78
+ before(:each) do
79
+ Config.expects(:require).with("deep_merge").raises(LoadError, "unable to load")
80
+ end
81
+
82
+ it "should error if merge_behavior is 'deep'" do
83
+ expect { Config.load(:merge_behavior => :deep) }.to raise_error(Hiera::Error, error_message)
84
+ end
85
+
86
+ it "should error if merge_behavior is 'deeper'" do
87
+ expect { Config.load(:merge_behavior => :deeper) }.to raise_error(Hiera::Error, error_message)
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#load_backends" do
93
+ it "should load each backend" do
94
+ Config.load(:backends => ["One", "Two"])
95
+ Config.expects(:require).with("hiera/backend/one_backend")
96
+ Config.expects(:require).with("hiera/backend/two_backend")
97
+ Config.load_backends
98
+ end
99
+
100
+ it "should warn if it cant load a backend" do
101
+ Config.load(:backends => ["one"])
102
+ Config.expects(:require).with("hiera/backend/one_backend").raises("fail")
103
+
104
+ expect {
105
+ Config.load_backends
106
+ }.to raise_error("fail")
107
+ end
108
+ end
109
+
110
+ describe "#include?" do
111
+ it "should correctly report inclusion" do
112
+ Config.load({})
113
+ Config.include?(:foo).should == false
114
+ Config.include?(:logger).should == true
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ class Hiera
4
+ describe Console_logger do
5
+ describe "#warn" do
6
+ it "should warn to STDERR" do
7
+ STDERR.expects(:puts).with("WARN: 0: foo")
8
+ Time.expects(:now).returns(0)
9
+ Console_logger.warn("foo")
10
+ end
11
+
12
+ it "should debug to STDERR" do
13
+ STDERR.expects(:puts).with("DEBUG: 0: foo")
14
+ Time.expects(:now).returns(0)
15
+ Console_logger.debug("foo")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,80 @@
1
+ require 'hiera/fallback_logger'
2
+
3
+ describe Hiera::FallbackLogger do
4
+ before :each do
5
+ InMemoryLogger.reset
6
+ SuitableLogger.reset
7
+ end
8
+
9
+ it "delegates #warn to the logger implemenation" do
10
+ logger = Hiera::FallbackLogger.new(InMemoryLogger)
11
+
12
+ logger.warn("the message")
13
+
14
+ InMemoryLogger.warnings.should == ["the message"]
15
+ end
16
+
17
+ it "delegates #debug to the logger implemenation" do
18
+ logger = Hiera::FallbackLogger.new(InMemoryLogger)
19
+
20
+ logger.debug("the message")
21
+
22
+ InMemoryLogger.debugs.should == ["the message"]
23
+ end
24
+
25
+ it "chooses the first logger that is suitable" do
26
+ logger = Hiera::FallbackLogger.new(UnsuitableLogger, SuitableLogger)
27
+
28
+ logger.warn("for the suitable logger")
29
+
30
+ SuitableLogger.warnings.should include("for the suitable logger")
31
+ end
32
+
33
+ it "raises an error if no implementation is suitable" do
34
+ expect do
35
+ Hiera::FallbackLogger.new(UnsuitableLogger)
36
+ end.to raise_error "No suitable logging implementation found."
37
+ end
38
+
39
+ it "issues a warning for each implementation that is not suitable" do
40
+ Hiera::FallbackLogger.new(UnsuitableLogger, UnsuitableLogger, SuitableLogger)
41
+
42
+ SuitableLogger.warnings.should == [
43
+ "Not using UnsuitableLogger. It does not report itself to be suitable.",
44
+ "Not using UnsuitableLogger. It does not report itself to be suitable."]
45
+ end
46
+
47
+ # Preserves log messages in memory
48
+ # and also serves as a "legacy" logger that has no
49
+ # suitable? method
50
+ class InMemoryLogger
51
+ class << self
52
+ attr_accessor :warnings, :debugs
53
+ end
54
+
55
+ def self.reset
56
+ self.warnings = []
57
+ self.debugs = []
58
+ end
59
+
60
+ def self.warn(message)
61
+ self.warnings << message
62
+ end
63
+
64
+ def self.debug(message)
65
+ self.debugs << message
66
+ end
67
+ end
68
+
69
+ class UnsuitableLogger
70
+ def self.suitable?
71
+ false
72
+ end
73
+ end
74
+
75
+ class SuitableLogger < InMemoryLogger
76
+ def self.suitable?
77
+ true
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+
4
+ class Hiera
5
+ describe Filecache do
6
+ before do
7
+ @cache = Filecache.new
8
+ end
9
+
10
+ def write_file(file, contents)
11
+ File.open(file, 'w') do |f|
12
+ f.write(contents)
13
+ end
14
+ end
15
+
16
+ describe "#read" do
17
+ it "reads data from a file" do
18
+ Dir.mktmpdir do |dir|
19
+ file = File.join(dir, "testing")
20
+ write_file(file, "my data")
21
+
22
+ @cache.read(file).should == "my data"
23
+ end
24
+ end
25
+
26
+ it "rereads data when the file changes" do
27
+ Dir.mktmpdir do |dir|
28
+ file = File.join(dir, "testing")
29
+ write_file(file, "my data")
30
+ @cache.read(file).should == "my data"
31
+
32
+ write_file(file, "changed data")
33
+ @cache.read(file).should == "changed data"
34
+ end
35
+ end
36
+
37
+ it "uses the provided default when the type does not match the expected type" do
38
+ Hiera.expects(:debug).with(regexp_matches(/String.*not.*Hash, setting defaults/))
39
+ Dir.mktmpdir do |dir|
40
+ file = File.join(dir, "testing")
41
+ write_file(file, "my data")
42
+ data = @cache.read(file, Hash, { :testing => "hash" }) do |data|
43
+ "a string"
44
+ end
45
+
46
+ data.should == { :testing => "hash" }
47
+ end
48
+ end
49
+
50
+ it "traps any errors from the block and uses the default value" do
51
+ Hiera.expects(:debug).with(regexp_matches(/Reading data.*failed:.*testing error/))
52
+ Dir.mktmpdir do |dir|
53
+ file = File.join(dir, "testing")
54
+ write_file(file, "my data")
55
+ data = @cache.read(file, Hash, { :testing => "hash" }) do |data|
56
+ raise ArgumentError, "testing error"
57
+ end
58
+
59
+ data.should == { :testing => "hash" }
60
+ end
61
+ end
62
+
63
+ it "raises an error when there is no default given and there is a problem" do
64
+ Dir.mktmpdir do |dir|
65
+ file = File.join(dir, "testing")
66
+ write_file(file, "my data")
67
+
68
+ expect do
69
+ @cache.read(file, Hash) do |data|
70
+ raise ArgumentError, "testing error"
71
+ end
72
+ end.to raise_error(ArgumentError, "testing error")
73
+ end
74
+ end
75
+ end
76
+
77
+ describe "#read_file" do
78
+ it "reads data from a file" do
79
+ Dir.mktmpdir do |dir|
80
+ file = File.join(dir, "testing")
81
+ write_file(file, "my data")
82
+
83
+ @cache.read_file(file).should == "my data"
84
+ end
85
+ end
86
+
87
+ it "rereads data when the file changes" do
88
+ Dir.mktmpdir do |dir|
89
+ file = File.join(dir, "testing")
90
+ write_file(file, "my data")
91
+ @cache.read_file(file).should == "my data"
92
+
93
+ write_file(file, "changed data")
94
+ @cache.read_file(file).should == "changed data"
95
+ end
96
+ end
97
+
98
+ it "errors when the type does not match the expected type" do
99
+ Dir.mktmpdir do |dir|
100
+ file = File.join(dir, "testing")
101
+ write_file(file, "my data")
102
+
103
+ expect do
104
+ @cache.read_file(file, Hash) do |data|
105
+ "a string"
106
+ end
107
+ end.to raise_error(TypeError)
108
+ end
109
+ end
110
+
111
+ it "converts the read data using the block" do
112
+ Dir.mktmpdir do |dir|
113
+ file = File.join(dir, "testing")
114
+ write_file(file, "my data")
115
+
116
+ @cache.read_file(file, Hash) do |data|
117
+ { :data => data }
118
+ end.should == { :data => "my data" }
119
+ end
120
+ end
121
+
122
+ it "errors when the file does not exist" do
123
+ expect do
124
+ @cache.read_file("/notexist")
125
+ end.to raise_error(Errno::ENOENT)
126
+ end
127
+
128
+ it "propogates any errors from the block" do
129
+ Dir.mktmpdir do |dir|
130
+ file = File.join(dir, "testing")
131
+ write_file(file, "my data")
132
+
133
+ expect do
134
+ @cache.read_file(file) do |data|
135
+ raise ArgumentError, "testing error"
136
+ end
137
+ end.to raise_error(ArgumentError, "testing error")
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,6 @@
1
+ :backends:
2
+ - yaml
3
+
4
+ :hierarchy:
5
+ - recursive
6
+ - niltest
@@ -0,0 +1,2 @@
1
+ niltest: 'Missing key #%{hiera("knotfound")}#. Key with nil #%{hiera("knil")}#'
2
+ knil: null
@@ -0,0 +1,3 @@
1
+ foo: '%{hiera("bar")}'
2
+
3
+ bar: '%{hiera("foo")}'
@@ -0,0 +1,5 @@
1
+ :backends:
2
+ - yaml
3
+
4
+ :hierarchy:
5
+ - common
@@ -0,0 +1 @@
1
+ bar: 'alternate'
@@ -0,0 +1,2 @@
1
+ foo: '%{hiera("bar")}'
2
+ bar: 'common'
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'hiera/util'
3
+
4
+ # This is only around for the logger setup tests
5
+ module Hiera::Foo_logger
6
+ end
7
+
8
+ describe "Hiera" do
9
+ describe "#logger=" do
10
+ it "loads the given logger" do
11
+ Hiera.expects(:require).with("hiera/foo_logger")
12
+
13
+ Hiera.logger = "foo"
14
+ end
15
+
16
+ it "falls back to the Console logger when the logger could not be loaded" do
17
+ Hiera.expects(:warn)
18
+
19
+ Hiera.logger = "no_such_logger"
20
+
21
+ Hiera.logger.should be Hiera::Console_logger
22
+ end
23
+
24
+ it "falls back to the Console logger when the logger class could not be found" do
25
+ Hiera.expects(:warn)
26
+ Hiera.expects(:require).with("hiera/no_constant_logger")
27
+
28
+ Hiera.logger = "no_constant"
29
+
30
+ Hiera.logger.should be Hiera::Console_logger
31
+ end
32
+ end
33
+
34
+ describe "#warn" do
35
+ it "delegates to the configured logger" do
36
+ Hiera.logger = 'console'
37
+ Hiera::Console_logger.expects(:warn).with("rspec")
38
+
39
+ Hiera.warn("rspec")
40
+ end
41
+ end
42
+
43
+ describe "#debug" do
44
+ it "delegates to the configured logger" do
45
+ Hiera.logger = 'console'
46
+ Hiera::Console_logger.expects(:debug).with("rspec")
47
+
48
+ Hiera.debug("rspec")
49
+ end
50
+ end
51
+
52
+ describe "#initialize" do
53
+ it "uses a default config file when none is provided" do
54
+ config_file = File.join(Hiera::Util.config_dir, 'hiera.yaml')
55
+ Hiera::Config.expects(:load).with(config_file)
56
+ Hiera::Config.stubs(:load_backends)
57
+ Hiera.new
58
+ end
59
+
60
+ it "passes the supplied config to the config class" do
61
+ Hiera::Config.expects(:load).with({"test" => "rspec"})
62
+ Hiera::Config.stubs(:load_backends)
63
+ Hiera.new(:config => {"test" => "rspec"})
64
+ end
65
+
66
+ it "loads all backends on start" do
67
+ Hiera::Config.stubs(:load)
68
+ Hiera::Config.expects(:load_backends)
69
+ Hiera.new
70
+ end
71
+ end
72
+
73
+ describe "#lookup" do
74
+ it "delegates to the Backend#lookup method" do
75
+ Hiera::Config.stubs(:load)
76
+ Hiera::Config.stubs(:load_backends)
77
+ Hiera::Backend.expects(:lookup).with(:key, :default, :scope, :order_override, :resolution_type)
78
+ Hiera.new.lookup(:key, :default, :scope, :order_override, :resolution_type)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'hiera/util'
3
+
4
+ describe "Hiera" do
5
+ context "when doing interpolation" do
6
+ let(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'interpolate') }
7
+
8
+ it 'should prevent endless recursion' do
9
+ Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
10
+ hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
11
+ expect do
12
+ hiera.lookup('foo', nil, {})
13
+ end.to raise_error Hiera::InterpolationLoop, 'Detected in [hiera("bar"), hiera("foo")]'
14
+ end
15
+ end
16
+
17
+ context "when not finding value for interpolated key" do
18
+ let(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'interpolate') }
19
+
20
+ it 'should resolve the interpolation to an empty string' do
21
+ Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
22
+ hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
23
+ expect(hiera.lookup('niltest', nil, {})).to eq('Missing key ##. Key with nil ##')
24
+ end
25
+ end
26
+
27
+ context "when doing interpolation with override" do
28
+ let(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'override') }
29
+
30
+ it 'should resolve interpolation using the override' do
31
+ Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
32
+ hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
33
+ expect(hiera.lookup('foo', nil, {}, 'alternate')).to eq('alternate')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ require 'hiera/puppet_logger'
2
+
3
+ describe Hiera::Puppet_logger do
4
+ it "is not suitable when Puppet is not defined" do
5
+ ensure_puppet_not_defined
6
+
7
+ Hiera::Puppet_logger.suitable?.should == false
8
+ end
9
+
10
+ it "is suitable when Puppet is defined" do
11
+ ensure_puppet_defined
12
+
13
+ Hiera::Puppet_logger.suitable?.should == true
14
+ end
15
+
16
+ after :each do
17
+ ensure_puppet_not_defined
18
+ end
19
+
20
+ def ensure_puppet_defined
21
+ if !Kernel.const_defined? :Puppet
22
+ Kernel.const_set(:Puppet, "Fake Puppet")
23
+ end
24
+ end
25
+
26
+ def ensure_puppet_not_defined
27
+ if Kernel.const_defined? :Puppet
28
+ Kernel.send(:remove_const, :Puppet)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hiera::Util do
4
+ describe 'Hiera::Util.posix?' do
5
+ it 'should return true on posix systems' do
6
+ Etc.expects(:getpwuid).with(0).returns(true)
7
+ Hiera::Util.posix?.should be_true
8
+ end
9
+
10
+ it 'should return false on non posix systems' do
11
+ Etc.expects(:getpwuid).with(0).returns(nil)
12
+ Hiera::Util.posix?.should be_false
13
+ end
14
+ end
15
+
16
+ describe 'Hiera::Util.microsoft_windows?' do
17
+ it 'should return false on posix systems' do
18
+ Hiera::Util.expects(:file_alt_separator).returns(nil)
19
+ Hiera::Util.microsoft_windows?.should be_false
20
+ end
21
+ end
22
+
23
+ describe 'Hiera::Util.config_dir' do
24
+ it 'should return the correct path for posix systems' do
25
+ Hiera::Util.expects(:file_alt_separator).returns(nil)
26
+ Hiera::Util.config_dir.should == '/etc/puppetlabs/code'
27
+ end
28
+
29
+ it 'should return the correct path for microsoft windows systems' do
30
+ Hiera::Util.expects(:microsoft_windows?).returns(true)
31
+ Hiera::Util.expects(:common_appdata).returns('C:\\ProgramData')
32
+ Hiera::Util.config_dir.should == 'C:\\ProgramData/PuppetLabs/code'
33
+ end
34
+ end
35
+
36
+ describe 'Hiera::Util.var_dir' do
37
+ it 'should return the correct path for posix systems' do
38
+ Hiera::Util.expects(:file_alt_separator).returns(nil)
39
+ Hiera::Util.var_dir.should == '/etc/puppetlabs/code/hieradata'
40
+ end
41
+
42
+ it 'should return the correct path for microsoft windows systems' do
43
+ Hiera::Util.expects(:microsoft_windows?).returns(true)
44
+ Hiera::Util.expects(:common_appdata).returns('C:\\ProgramData')
45
+ Hiera::Util.var_dir.should == 'C:\\ProgramData/PuppetLabs/code/hieradata'
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,44 @@
1
+ require "spec_helper"
2
+ require "hiera/version"
3
+ require 'pathname'
4
+
5
+ describe "Hiera.version Public API" do
6
+ subject() { Hiera }
7
+
8
+ before :each do
9
+ Hiera.instance_eval do
10
+ if @hiera_version
11
+ @hiera_version = nil
12
+ end
13
+ end
14
+ end
15
+
16
+ context "without a VERSION file" do
17
+ before :each do
18
+ subject.stubs(:read_version_file).returns(nil)
19
+ end
20
+
21
+ it "is Hiera::VERSION" do
22
+ subject.version.should == Hiera::VERSION
23
+ end
24
+ it "respects the version= setter" do
25
+ subject.version = '1.2.3'
26
+ subject.version.should == '1.2.3'
27
+ end
28
+ end
29
+
30
+ context "with a VERSION file" do
31
+ it "is the content of the file" do
32
+ subject.expects(:read_version_file).with() do |path|
33
+ pathname = Pathname.new(path)
34
+ pathname.basename.to_s == "VERSION"
35
+ end.returns('1.2.1-9-g9fda440')
36
+
37
+ subject.version.should == '1.2.1-9-g9fda440'
38
+ end
39
+ it "respects the version= setter" do
40
+ subject.version = '1.2.3'
41
+ subject.version.should == '1.2.3'
42
+ end
43
+ end
44
+ end