summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/network/format.rb37
-rw-r--r--lib/puppet/network/format_handler.rb46
-rwxr-xr-xspec/unit/network/format.rb130
-rwxr-xr-xspec/unit/network/format_handler.rb152
4 files changed, 252 insertions, 113 deletions
diff --git a/lib/puppet/network/format.rb b/lib/puppet/network/format.rb
index 7c678568d..832697836 100644
--- a/lib/puppet/network/format.rb
+++ b/lib/puppet/network/format.rb
@@ -23,5 +23,42 @@ class Puppet::Network::Format
end
instance_eval(&block) if block_given?
+
+ @intern_method = "from_%s" % name
+ @render_method = "to_%s" % name
+ @intern_multiple_method = "from_multiple_%s" % name
+ @render_multiple_method = "to_multiple_%s" % name
+ end
+
+ def intern(klass, text)
+ return klass.send(intern_method, text) if klass.respond_to?(intern_method)
+ raise NotImplementedError
+ end
+
+ def intern_multiple(klass, text)
+ return klass.send(intern_multiple_method, text) if klass.respond_to?(intern_multiple_method)
+ raise NotImplementedError
+ end
+
+ def render(instance)
+ return instance.send(render_method) if instance.respond_to?(render_method)
+ raise NotImplementedError
end
+
+ def render_multiple(instances)
+ # This method implicitly assumes that all instances are of the same type.
+ return instances[0].class.send(render_multiple_method, instances) if instances[0].class.respond_to?(render_multiple_method)
+ raise NotImplementedError
+ end
+
+ def supported?(klass)
+ klass.respond_to?(intern_method) and
+ klass.respond_to?(intern_multiple_method) and
+ klass.respond_to?(render_multiple_method) and
+ klass.instance_methods.include?(render_method)
+ end
+
+ private
+
+ attr_reader :intern_method, :render_method, :intern_multiple_method, :render_multiple_method
end
diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb
index 7e540708d..e42cc4c46 100644
--- a/lib/puppet/network/format_handler.rb
+++ b/lib/puppet/network/format_handler.rb
@@ -1,3 +1,4 @@
+require 'yaml'
require 'puppet/network'
require 'puppet/network/format'
@@ -23,31 +24,34 @@ module Puppet::Network::FormatHandler
@formats[name]
end
+ # Provide a list of all formats.
+ def self.formats
+ @formats.keys
+ end
+
# Return a format capable of handling the provided mime type.
def self.mime(mimetype)
@formats.values.find { |format| format.mime == mimetype }
end
module ClassMethods
+ def format_handler
+ Puppet::Network::FormatHandler
+ end
+
def convert_from(format, data)
raise ArgumentError, "Format %s not supported" % format unless support_format?(format)
- send("from_%s" % format, data)
+ format_handler.format(format).intern(self, data)
end
def convert_from_multiple(format, data)
- if respond_to?("from_multiple_%s" % format)
- send("from_multiple_%s" % format, data)
- else
- convert_from(format, data)
- end
+ raise ArgumentError, "Format %s not supported" % format unless support_format?(format)
+ format_handler.format(format).intern_multiple(self, data)
end
def render_multiple(format, instances)
- if respond_to?("to_multiple_%s" % format)
- send("to_multiple_%s" % format, instances)
- else
- instances.send("to_%s" % format)
- end
+ raise ArgumentError, "Format %s not supported" % format unless support_format?(format)
+ format_handler.format(format).render_multiple(instances)
end
def default_format
@@ -55,15 +59,19 @@ module Puppet::Network::FormatHandler
end
def support_format?(name)
- respond_to?("from_%s" % name) and instance_methods.include?("to_%s" % name)
+ Puppet::Network::FormatHandler.format(name).supported?(self)
end
def supported_formats
- instance = instance_methods.collect { |m| m =~ /^to_(.+)$/ and $1 }.compact
- klass = methods.collect { |m| m =~ /^from_(.+)$/ and $1 }.compact
+ format_handler.formats.collect { |f| format_handler.format(f) }.find_all { |f| f.supported?(self) }.collect { |f| f.name }
+ end
- # Return the intersection of the two lists.
- return instance & klass
+ def from_marshal(text)
+ Marshal.load(text)
+ end
+
+ def from_yaml(text)
+ YAML.load(text)
end
end
@@ -75,12 +83,16 @@ module Puppet::Network::FormatHandler
format = self.class.default_format
end
- send("to_%s" % format)
+ Puppet::Network::FormatHandler.format(format).render(self)
end
def support_format?(name)
self.class.support_format?(name)
end
+
+ def to_marshal(instance)
+ Marshal.dump(instance)
+ end
end
end
diff --git a/spec/unit/network/format.rb b/spec/unit/network/format.rb
index 78e677e9b..34a841603 100755
--- a/spec/unit/network/format.rb
+++ b/spec/unit/network/format.rb
@@ -4,35 +4,129 @@ require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/format'
-describe Puppet::Network::Format do
- it "should require a name" do
- lambda { Puppet::Network::Format.new }.should raise_error(ArgumentError)
+# A class with all of the necessary
+# hooks.
+class FormatRenderer
+ def self.to_multiple_my_format(list)
end
- it "should be able to provide its name" do
- Puppet::Network::Format.new(:my_format).name.should == :my_format
+ def self.from_multiple_my_format(text)
end
- it "should be able to set its mime type at initialization" do
- format = Puppet::Network::Format.new(:my_format, :mime => "foo/bar")
- format.mime.should == "foo/bar"
+ def self.from_my_format(text)
end
- it "should default to text plus the name of the format as the mime type" do
- Puppet::Network::Format.new(:my_format).mime.should == "text/my_format"
+ def to_my_format
end
+end
+
+describe Puppet::Network::Format do
+ describe "when initializing" do
+ it "should require a name" do
+ lambda { Puppet::Network::Format.new }.should raise_error(ArgumentError)
+ end
+
+ it "should be able to provide its name" do
+ Puppet::Network::Format.new(:my_format).name.should == :my_format
+ end
+
+ it "should be able to set its mime type at initialization" do
+ format = Puppet::Network::Format.new(:my_format, :mime => "foo/bar")
+ format.mime.should == "foo/bar"
+ end
- it "should fail if unsupported options are provided" do
- lambda { Puppet::Network::Format.new(:my_format, :foo => "bar") }.should raise_error(ArgumentError)
+ it "should default to text plus the name of the format as the mime type" do
+ Puppet::Network::Format.new(:my_format).mime.should == "text/my_format"
+ end
+
+ it "should fail if unsupported options are provided" do
+ lambda { Puppet::Network::Format.new(:my_format, :foo => "bar") }.should raise_error(ArgumentError)
+ end
end
- it "should support being confined" do
- Puppet::Network::Format.new(:my_format).should respond_to(:confine)
+ describe "instances" do
+ before do
+ @format = Puppet::Network::Format.new(:my_format)
+ end
+
+ it "should support being confined" do
+ @format.should respond_to(:confine)
+ end
+
+ it "should not be considered suitable if confinement conditions are not met" do
+ @format.confine :true => false
+ @format.should_not be_suitable
+ end
+
+ it "should be able to determine if a class is supported" do
+ @format.should respond_to(:supported?)
+ end
+
+ it "should consider a class to be supported if it has the individual and multiple methods for rendering and interning" do
+ @format.should be_supported(FormatRenderer)
+ end
+
+ it "should not consider a class to be supported unless it has the individual and multiple methods for rendering and interning" do
+ Puppet::Network::Format.new(:yaml).should_not be_supported(String)
+ end
end
- it "should not be considered suitable if confinement conditions are not met" do
- format = Puppet::Network::Format.new(:my_format)
- format.confine :true => false
- format.should_not be_suitable
+ describe "when converting between instances and formatted text" do
+ before do
+ @format = Puppet::Network::Format.new(:my_format)
+ @instance = FormatRenderer.new
+ end
+
+ it "should have a method for rendering a single instance" do
+ @format.should respond_to(:render)
+ end
+
+ it "should have a method for rendering multiple instances" do
+ @format.should respond_to(:render_multiple)
+ end
+
+ it "should have a method for interning text" do
+ @format.should respond_to(:intern)
+ end
+
+ it "should have a method for interning text into multiple instances" do
+ @format.should respond_to(:intern_multiple)
+ end
+
+ it "should return the results of calling the instance-specific render method if the method is present" do
+ @instance.expects(:to_my_format).returns "foo"
+ @format.render(@instance).should == "foo"
+ end
+
+ it "should return the results of calling the class-specific render_multiple method if the method is present" do
+ @instance.class.expects(:to_multiple_my_format).returns ["foo"]
+ @format.render_multiple([@instance]).should == ["foo"]
+ end
+
+ it "should return the results of calling the class-specific intern method if the method is present" do
+ FormatRenderer.expects(:from_my_format).with("foo").returns @instance
+ @format.intern(FormatRenderer, "foo").should equal(@instance)
+ end
+
+ it "should return the results of calling the class-specific intern_multiple method if the method is present" do
+ FormatRenderer.expects(:from_multiple_my_format).with("foo").returns [@instance]
+ @format.intern_multiple(FormatRenderer, "foo").should == [@instance]
+ end
+
+ it "should fail if asked to render and the instance does not respond to 'to_<format>'" do
+ lambda { @format.render("foo") }.should raise_error(NotImplementedError)
+ end
+
+ it "should fail if asked to intern and the class does not respond to 'from_<format>'" do
+ lambda { @format.intern(String, "foo") }.should raise_error(NotImplementedError)
+ end
+
+ it "should fail if asked to intern multiple and the class does not respond to 'from_multiple_<format>'" do
+ lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError)
+ end
+
+ it "should fail if asked to render multiple and the instance does not respond to 'to_multiple_<format>'" do
+ lambda { @format.render_multiple(["foo", "bar"]) }.should raise_error(NotImplementedError)
+ end
end
end
diff --git a/spec/unit/network/format_handler.rb b/spec/unit/network/format_handler.rb
index d142c3177..5071196c3 100755
--- a/spec/unit/network/format_handler.rb
+++ b/spec/unit/network/format_handler.rb
@@ -6,26 +6,6 @@ require 'puppet/network/format_handler'
class FormatTester
extend Puppet::Network::FormatHandler
-
- # Not a supported format; missing the 'to'
- def self.from_nothing; end
-
- # Not a supported format; missing the 'from'
- def to_nowhere; end
-
- # A largely functional format.
- def self.from_good; end
-
- def to_good; end
-
- # A format that knows how to handle multiple instances specially.
- def self.from_mults; end
-
- def self.from_multiple_mults; end
-
- def self.to_multiple_mults; end
-
- def to_mults; end
end
describe Puppet::Network::FormatHandler do
@@ -36,68 +16,69 @@ describe Puppet::Network::FormatHandler do
end
end
- it "should be able to test whether a format is supported" do
- FormatTester.should respond_to(:support_format?)
- end
-
- it "should consider the format supported if it can convert from an instance to the format and from the format to an instance" do
- FormatTester.should be_support_format(:good)
+ it "should be able to list supported formats" do
+ FormatTester.should respond_to(:supported_formats)
end
- it "should not consider the format supported unless it can convert the instance to the specified format" do
- FormatTester.should_not be_support_format(:nothing)
+ it "should include all supported formats" do
+ one = stub 'supported', :supported? => true, :name => "one"
+ two = stub 'supported', :supported? => false, :name => "two"
+ three = stub 'supported', :supported? => true, :name => "three"
+ four = stub 'supported', :supported? => false, :name => "four"
+ Puppet::Network::FormatHandler.expects(:formats).returns %w{one two three four}
+ Puppet::Network::FormatHandler.expects(:format).with("one").returns one
+ Puppet::Network::FormatHandler.expects(:format).with("two").returns two
+ Puppet::Network::FormatHandler.expects(:format).with("three").returns three
+ Puppet::Network::FormatHandler.expects(:format).with("four").returns four
+ FormatTester.supported_formats.sort.should == %w{one three}.sort
end
- it "should not consider the format supported unless it can convert from the format to an instance" do
- FormatTester.should_not be_support_format(:nowhere)
+ it "should return the first format as the default format" do
+ FormatTester.expects(:supported_formats).returns %w{one two}
+ FormatTester.default_format.should == "one"
end
- it "should be able to convert from a given format" do
- FormatTester.should respond_to(:convert_from)
- end
+ describe "when using formats" do
+ before do
+ @format = mock 'format'
+ Puppet::Network::FormatHandler.stubs(:format).with(:my_format).returns @format
+ @format.stubs(:supported?).returns true
+ end
- it "should fail if asked to convert from an unsupported format" do
- FormatTester.expects(:support_format?).with(:nope).returns false
- lambda { FormatTester.convert_from(:nope, "mydata") }.should raise_error(ArgumentError)
- end
+ it "should be able to test whether a format is supported" do
+ FormatTester.should respond_to(:support_format?)
+ end
- it "should call the format-specific converter when asked to convert from a given format" do
- FormatTester.expects(:from_good).with("mydata")
- FormatTester.convert_from(:good, "mydata")
- end
+ it "should use the Format to determine whether a given format is supported" do
+ @format.expects(:supported?).with(FormatTester)
+ FormatTester.support_format?(:my_format)
+ end
- it "should be able to use a specific hook for converting into multiple instances" do
- FormatTester.expects(:from_multiple_mults).with("mydata")
- FormatTester.convert_from_multiple(:mults, "mydata")
- end
+ it "should be able to convert from a given format" do
+ FormatTester.should respond_to(:convert_from)
+ end
- it "should default to the normal conversion method when no special method is available" do
- FormatTester.expects(:from_good).with("mydata")
- FormatTester.convert_from_multiple(:good, "mydata")
- end
+ it "should fail if asked to convert from an unsupported format" do
+ @format.expects(:supported?).with(FormatTester).returns false
+ lambda { FormatTester.convert_from(:my_format, "mydata") }.should raise_error(ArgumentError)
+ end
- it "should be able to use a specific hook for rendering multiple instances" do
- FormatTester.expects(:to_multiple_mults).with("mydata")
- FormatTester.render_multiple(:mults, "mydata")
- end
+ it "should call the format-specific converter when asked to convert from a given format" do
+ @format.expects(:intern).with(FormatTester, "mydata")
+ FormatTester.convert_from(:my_format, "mydata")
+ end
- it "should use the instance method if no multiple-render hook is available" do
- instances = mock 'instances'
- instances.expects(:to_good)
- FormatTester.render_multiple(:good, instances)
- end
+ it "should be able to use a specific hook for converting into multiple instances" do
+ @format.expects(:intern_multiple).with(FormatTester, "mydata")
- it "should be able to list supported formats" do
- FormatTester.should respond_to(:supported_formats)
- end
+ FormatTester.convert_from_multiple(:my_format, "mydata")
+ end
- it "should include all formats that include both the to_ and from_ methods in the list of supported formats" do
- FormatTester.supported_formats.sort.should == %w{good mults}.sort
- end
+ it "should be able to use a specific hook for rendering multiple instances" do
+ @format.expects(:render_multiple).with("mydata")
- it "should return the first format as the default format" do
- FormatTester.expects(:supported_formats).returns %w{one two}
- FormatTester.default_format.should == "one"
+ FormatTester.render_multiple(:my_format, "mydata")
+ end
end
describe "when managing formats" do
@@ -129,6 +110,20 @@ describe Puppet::Network::FormatHandler do
format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar")
Puppet::Network::FormatHandler.mime("foo/bar").should equal(format)
end
+
+ it "should be able to return all formats" do
+ one = stub 'one', :name => :one
+ two = stub 'two', :name => :two
+ Puppet::Network::Format.expects(:new).with(:one).returns(one)
+ Puppet::Network::Format.expects(:new).with(:two).returns(two)
+
+ Puppet::Network::FormatHandler.create(:one)
+ Puppet::Network::FormatHandler.create(:two)
+
+ list = Puppet::Network::FormatHandler.formats
+ list.should be_include(:one)
+ list.should be_include(:two)
+ end
end
describe "when an instance" do
@@ -136,14 +131,6 @@ describe Puppet::Network::FormatHandler do
FormatTester.new.should respond_to(:support_format?)
end
- it "should consider the format supported if it can convert from an instance to the format and from the format to an instance" do
- FormatTester.new.should be_support_format(:good)
- end
-
- it "should not consider the format supported unless it can convert from an instance to the format and from the format to an instance" do
- FormatTester.new.should_not be_support_format(:nope)
- end
-
it "should be able to convert to a given format" do
FormatTester.new.should respond_to(:render)
end
@@ -155,15 +142,24 @@ describe Puppet::Network::FormatHandler do
end
it "should call the format-specific converter when asked to convert to a given format" do
+ format = stub 'rendering format', :supported? => true
+
+ Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format
+
tester = FormatTester.new
- tester.expects(:to_good)
- tester.render(:good)
+ format.expects(:render).with(tester).returns "foo"
+
+ tester.render(:foo).should == "foo"
end
it "should render to the default format if no format is provided when rendering" do
+ format = stub 'rendering format', :supported? => true
+ Puppet::Network::FormatHandler.stubs(:format).with("foo").returns format
+
FormatTester.expects(:default_format).returns "foo"
tester = FormatTester.new
- tester.expects(:to_foo)
+
+ format.expects(:render).with(tester)
tester.render
end
end