diff --git a/lib/representable/hash.rb b/lib/representable/hash.rb index fe45cee8..d62859ed 100644 --- a/lib/representable/hash.rb +++ b/lib/representable/hash.rb @@ -26,6 +26,7 @@ def collection_representer_class def from_hash(data, options={}, binding_builder=Binding) data = filter_wrap(data, options) + raise TypeError, "Expected Hash, got #{data.class}." unless ::Hash === data update_properties_from(data, options, binding_builder) end diff --git a/lib/representable/hash/collection.rb b/lib/representable/hash/collection.rb index 9986e085..3e207e6d 100644 --- a/lib/representable/hash/collection.rb +++ b/lib/representable/hash/collection.rb @@ -19,6 +19,14 @@ def items(options={}, &block) # TODO: revise lonely collection and build separate pipeline where we just use Serialize, etc. + def from_hash(data, options={}, binding_builder=Binding) + data = filter_wrap(data, options) + data = [data] if ::Hash === data + raise TypeError, "Expected Enumerable, got #{data.class}." unless data.respond_to?(:each) + + update_properties_from(data, options, binding_builder) + end + def create_representation_with(doc, options, format) options = normalize_options(options) options[:_self] = options diff --git a/test/for_collection_test.rb b/test/for_collection_test.rb index f32b31dd..db9d2b16 100644 --- a/test/for_collection_test.rb +++ b/test/for_collection_test.rb @@ -69,6 +69,38 @@ module SongRepresenter it { parse(representer.for_collection.new([]), input).must_equal songs } end end - # with module including module -end \ No newline at end of file + + describe 'bad collections' do + let(:representer) { + Class.new(Representable::Decorator) do + include Representable::Hash + property :name + + collection_representer class: Song + end + } + + it 'parses when argument is an Array' do + representer.for_collection.new([]).from_hash([{ 'name' => 'Gateways' }]) + .must_equal [Song.new('Gateways')] + end + + it 'parses when argument is a Hash' do + representer.for_collection.new([]).from_hash('name' => 'Mother North') + .must_equal [Song.new('Mother North')] + end + + it 'raises a TypeError when argument is not an Enumerable' do + from_hash = -> { + representer.for_collection.new([]).from_hash(nil) + }.must_raise TypeError + from_hash.message.must_equal 'Expected Enumerable, got NilClass.' + + from_hash = -> { + representer.for_collection.new([]).from_hash('') + }.must_raise TypeError + from_hash.message.must_equal 'Expected Enumerable, got String.' + end + end +end diff --git a/test/hash_test.rb b/test/hash_test.rb index fdde8608..68421a3d 100644 --- a/test/hash_test.rb +++ b/test/hash_test.rb @@ -27,6 +27,13 @@ class HashWithScalarPropertyTest < MiniTest::Spec album.title.must_equal nil album.extend(representer).from_hash("title" => nil) end + + it 'raises a TypeError when argument is not a Hash' do + from_hash = -> { + album.extend(representer).from_hash('not Hashish') + }.must_raise TypeError + from_hash.message.must_equal 'Expected Hash, got String.' + end end end @@ -157,4 +164,4 @@ class HashWithScalarCollectionTest < MiniTest::Spec album.extend(representer).from_hash("songs" => ["Off Key Melody", "Sinking"]).must_equal Album.new(["Off Key Melody", "Sinking"]) end end -end \ No newline at end of file +end diff --git a/test/wrap_test.rb b/test/wrap_test.rb index 20783adb..7eb45df7 100644 --- a/test/wrap_test.rb +++ b/test/wrap_test.rb @@ -76,10 +76,15 @@ class BandDecorator < Representable::Decorator it do band.from_hash({"bands" => {"name"=>"Social Distortion"}}).name.must_equal "Social Distortion" - band.from_hash({"name"=>"Social Distortion"}, wrap: false).name.must_equal "Social Distortion" - band.from_hash({band: {"name"=>"Social Distortion"}}, wrap: :band).name.must_equal "Social Distortion" + band.from_hash({"name"=>"Bad Religion"}, wrap: false).name.must_equal "Bad Religion" + band.from_hash({"band"=>{"name"=>"Pennywise"}}, wrap: :band).name.must_equal "Pennywise" end + it 'raises a TypeError when unwrapped argument is not a Hash' do + -> { band.from_hash('bands' => '') }.must_raise TypeError + -> { band.from_hash('', wrap: false) }.must_raise TypeError + -> { band.from_hash({'band' => ''}, wrap: :band) }.must_raise TypeError + end class AlbumDecorator < Representable::Decorator include Representable::Hash @@ -149,4 +154,3 @@ class AlbumDecorator < Representable::Decorator # album.from_hash({"albums" => {"band" => {"name"=>"Rvivr"}}}).band.name.must_equal "Rvivr" # end end -