hashme 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4f9cb6f4cdaff6724a27b50649492558e063d895
4
+ data.tar.gz: 821a1a3dd493decc292af29ba65b25ded28a6ce8
5
+ SHA512:
6
+ metadata.gz: 2ce2e52be2471ebc0ea3a4e379d0b03722f9e393548e6daa22ace5f110e655198771161ccd3351a49cd9ab365f9a4d4ed6dab2c31525b58bedca5f2d700a43f8
7
+ data.tar.gz: 913eeffb93e61a1304dd37297b39f0e0b896a2e39f37d45ce100bac68c16ec320d3ceeb7f1c54ba6052148fe24c2e07c6b142acc772df794de99649639feb7e3
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hashme.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sam Lown
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Hashme
2
+
3
+ Hashes are great, but sometimes you need a bit more structure.
4
+
5
+ Hashme helps you create simple models that allow you to initialize and
6
+ generate hashes that you can serialize and store as you wish.
7
+
8
+ Its a bit like ActiveRecord, but without all the messy database stuff,
9
+ and of course you can nest to you're hearts content.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'hashme'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install hashme
24
+
25
+ ## Usage
26
+
27
+ Create a class, include the `Hashme` module, and define some properties:
28
+
29
+ ````ruby
30
+ # Our cat class!
31
+ class Cat
32
+ include Hashme
33
+
34
+ property :name, String
35
+ property :description, String
36
+ end
37
+
38
+ # Do something with it
39
+ kitty = Cat.new(:name => "Catso", :description => "Meows a lot")
40
+ kitty.name # Catso
41
+ kitty.to_hash # {:name => "Catso", :description => "Meows a lot"}
42
+ kitty.to_json # "{\"name\":\"Catso\",\"description\":\"Meows a lot\"}"
43
+
44
+ kitty2 = Cat.new(kitty.to_hash)
45
+ kitty2.to_hash == kitty.to_hash # true!
46
+ ````
47
+
48
+ Models can also be nested, which is probably the most useful part:
49
+
50
+ ````ruby
51
+ # A kennel full of kitties
52
+ class Kennel
53
+ include Hashme
54
+
55
+ property :name, String
56
+ property :location, Point
57
+ property :cats, [Cat]
58
+ end
59
+
60
+ # Build a kennel
61
+ kennel = Kennel.new(:name => "Goaway Kitty Home", :location => Point.new(40.333,-3.4555))
62
+
63
+ # Add a kitten using an object
64
+ kennel << kitty
65
+
66
+ # Add a new cat using a raw hash
67
+ kennel << {
68
+ :name => "Felix",
69
+ :description => "Black and white"
70
+ }
71
+
72
+ # Serialize and deserialize to recreate the whole structure
73
+ store = kennel.to_hash
74
+ kennel = Kennel.new(store)
75
+ kennel.cats.length == 2 # true!
76
+ ````
77
+
78
+ ## Contributing
79
+
80
+ 1. Fork it
81
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
82
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
83
+ 4. Push to the branch (`git push origin my-new-feature`)
84
+ 5. Create new Pull Request
85
+
86
+ ## Authors
87
+
88
+ * Sam Lown <me@samlown.com>
89
+
90
+ ## History
91
+
92
+ ### 0.1.0 - 2014-01-15
93
+
94
+ * First release!
95
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/hashme.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hashme/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hashme"
8
+ spec.version = Hashme::VERSION
9
+ spec.authors = ["Sam Lown"]
10
+ spec.email = ["me@samlown.com"]
11
+ spec.description = %q{Modeling with Hashes made easy.}
12
+ spec.summary = %q{Easily define simple models that can be easily serialized and de-serialized.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activemodel", "~> 3.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
data/lib/hashme.rb ADDED
@@ -0,0 +1,45 @@
1
+ require "hashme/version"
2
+
3
+ # External dependencies
4
+
5
+ require "active_model"
6
+ require "active_model/naming"
7
+ require "active_model/serialization"
8
+
9
+ require "active_support/core_ext"
10
+ require "active_support/json"
11
+
12
+ # Local dependencies
13
+
14
+ require "hashme/attributes"
15
+ require "hashme/castable"
16
+ require "hashme/casted_array"
17
+ require "hashme/properties"
18
+ require "hashme/property"
19
+
20
+ module Hashme
21
+ extend ActiveSupport::Concern
22
+
23
+ include ActiveModel::Validations
24
+
25
+ included do
26
+ include Castable
27
+ include Attributes
28
+ include Properties
29
+ # Eventually! include Validations
30
+ end
31
+
32
+ def initialize(attrs = {})
33
+ # Use the `Properties` module's `#set_attribtues` method
34
+ set_attributes(attrs)
35
+ end
36
+
37
+ module ClassMethods
38
+ # Little help. Equivalent to new.tap
39
+ def build(*attrs)
40
+ instance = self.new(*attrs)
41
+ yield instance if block_given?
42
+ instance
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ module Hashme
2
+ module Attributes
3
+ include Enumerable
4
+
5
+ extend Forwardable
6
+
7
+ def_delegators :_attributes, :to_a,
8
+ :==, :eql?, :keys, :values, :each,
9
+ :reject, :reject!, :empty?, :clear, :merge, :merge!,
10
+ :encode_json, :as_json, :to_json, :to_hash,
11
+ :frozen?
12
+
13
+ def []=(key, value)
14
+ _attributes[key.to_sym] = value
15
+ end
16
+
17
+ def [](key)
18
+ _attributes[key.to_sym]
19
+ end
20
+
21
+ def has_key?(key)
22
+ _attributes.has_key?(key.to_sym)
23
+ end
24
+
25
+ def delete(key)
26
+ _attributes.delete(key.to_sym)
27
+ end
28
+
29
+ def dup
30
+ new = super
31
+ @_attributes = @_attributes.dup
32
+ new
33
+ end
34
+
35
+ def clone
36
+ new = super
37
+ @_attributes = @_attributes.clone
38
+ new
39
+ end
40
+
41
+ def inspect
42
+ string = keys.collect{|key|
43
+ "#{key}: #{self[key].inspect}"
44
+ }.compact.join(", ")
45
+ "#<#{self.class} #{string}>"
46
+ end
47
+
48
+ private
49
+
50
+ def _attributes
51
+ @_attributes ||= {}
52
+ @_attributes
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,10 @@
1
+ module Hashme
2
+ module Castable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attr_accessor :casted_by
7
+ attr_accessor :casted_by_property
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,61 @@
1
+ require 'forwardable'
2
+
3
+ module Hashme
4
+
5
+ # The Hashme CastedArray is a special object wrapper that allows other Model's
6
+ # or Objects to be stored in an array, but maintain casted ownership.
7
+ #
8
+ # Adding objects will automatically assign the Array's owner, as opposed
9
+ # to the array itself.
10
+ #
11
+ class CastedArray
12
+ extend Forwardable
13
+ include Castable
14
+
15
+ def_delegators :@_array,
16
+ :to_a, :==, :eql?, :size,
17
+ :first, :last, :at, :length,
18
+ :each, :reject, :empty?, :map,
19
+ :clear, :pop, :shift, :delete, :delete_at,
20
+ :encode_json, :as_json, :to_json,
21
+ :inspect, :any?
22
+
23
+ def initialize(owner, property, values = [])
24
+ @_array = []
25
+ self.casted_by = owner
26
+ self.casted_by_property = property
27
+ if values.respond_to?(:each)
28
+ values.each do |value|
29
+ self.push(value)
30
+ end
31
+ end
32
+ end
33
+
34
+ def <<(obj)
35
+ @_array << instantiate_and_build(obj)
36
+ end
37
+
38
+ def push(obj)
39
+ @_array.push(instantiate_and_build(obj))
40
+ end
41
+
42
+ def unshift(obj)
43
+ @_array.unshift(instantiate_and_build(obj))
44
+ end
45
+
46
+ def [] index
47
+ @_array[index]
48
+ end
49
+
50
+ def []= index, obj
51
+ @_array[index] = instantiate_and_build(obj)
52
+ end
53
+
54
+ protected
55
+
56
+ def instantiate_and_build(obj)
57
+ casted_by_property.build(casted_by, obj)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,80 @@
1
+ module Hashme
2
+ module Properties
3
+ extend ActiveSupport::Concern
4
+
5
+ def get_attribute(name)
6
+ self[name]
7
+ end
8
+
9
+ def set_attribute(name, value)
10
+ property = get_property(name)
11
+ if property.nil?
12
+ self[name.to_sym] = value
13
+ else
14
+ self[property.name] = value.present? ? property.cast(self, value) : value
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ # Internal method to go through each attribute and set the
21
+ # values via the set_attribute method.
22
+ def set_attributes(attrs = {})
23
+ attrs.each do |key, value|
24
+ set_attribute(key, value)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def get_property(name)
31
+ # not only search in the class, search in the superclass too if the superclass can respond to properties[]. Using a class method for this
32
+ self.class.search_property(name)
33
+ end
34
+
35
+ module ClassMethods
36
+
37
+ attr_accessor :properties
38
+
39
+ def property(*args)
40
+ self.properties ||= {}
41
+
42
+ # Prepare the property object and methods
43
+ property = Property.new(*args)
44
+ properties[property.name] = property
45
+ define_property_methods(property)
46
+
47
+ property
48
+ end
49
+
50
+ # Recursive search the property in the superclass chain
51
+ def search_property(name)
52
+ name = name.to_sym
53
+
54
+ if properties[name]
55
+ properties[name]
56
+ elsif superclass.respond_to?(:search_property)
57
+ superclass.search_property(name)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ protected
64
+
65
+ def define_property_methods(property)
66
+ # Getter
67
+ define_method(property.name) do
68
+ get_attribute(property.name) || property.default
69
+ end
70
+ # Setter
71
+ define_method "#{property.name}=" do |value|
72
+ set_attribute(property.name, value)
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ end
80
+ end
@@ -0,0 +1,63 @@
1
+ module Hashme
2
+ class Property
3
+
4
+ attr_accessor :name, :type, :default
5
+
6
+ def initialize(name, type, opts = {})
7
+ self.name = name.to_sym
8
+
9
+ # Always set type to base type
10
+ if type.is_a?(Array) && !type.first.nil?
11
+ @_use_casted_array = true
12
+ klass = type.first
13
+ else
14
+ @_use_casted_array = false
15
+ klass = type
16
+ end
17
+
18
+ self.type = klass
19
+
20
+ # Handle options
21
+ self.default = opts[:default]
22
+ end
23
+
24
+ def to_s
25
+ name.to_s
26
+ end
27
+
28
+ def to_sym
29
+ name
30
+ end
31
+
32
+ # Use cast method when we do not know if we may need to handle a
33
+ # casted array of objects.
34
+ def cast(owner, value)
35
+ if use_casted_array?
36
+ CastedArray.new(owner, self, value)
37
+ else
38
+ build(owner, value)
39
+ end
40
+ end
41
+
42
+ # Build a new object of the type defined by the property.
43
+ # Will not deal create CastedArrays!
44
+ def build(owner, value)
45
+ obj = nil
46
+ if value.is_a?(type)
47
+ obj = value
48
+ elsif type == Date
49
+ obj = type.parse(value)
50
+ else
51
+ obj = type.new(value)
52
+ end
53
+ obj.casted_by = owner if obj.respond_to?(:casted_by=)
54
+ obj.casted_by_property = self if obj.respond_to?(:casted_by_property=)
55
+ obj
56
+ end
57
+
58
+ def use_casted_array?
59
+ @_use_casted_array
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Hashme
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashme::Attributes do
4
+
5
+
6
+ before :each do
7
+ @model = Class.new do
8
+ include Hashme
9
+ end
10
+ @obj = @model.new
11
+ end
12
+
13
+ let :attribs do
14
+ @obj.send(:_attributes)
15
+ end
16
+
17
+ describe "forwarded methods" do
18
+ before :each do
19
+ @hash = {:key1 => 'value1', :key2 => 'value2'}
20
+ @obj[:key1] = 'value1'
21
+ @obj[:key2] = 'value2'
22
+ end
23
+
24
+ it "should assign some of the basic hash methods" do
25
+ (@obj == @hash).should be_true
26
+ @obj.eql?(@hash).should be_true
27
+ @obj.keys.should eql(@hash.keys)
28
+ @obj.values.should eql(@hash.values)
29
+ @obj.to_hash.should eql(@hash)
30
+ end
31
+ end
32
+
33
+ describe "#[]=" do
34
+ it "should assign values to attributes hash" do
35
+ @obj[:akey] = "test"
36
+ attribs[:akey].should eql("test")
37
+ @obj['akey'] = "anothertest"
38
+ attribs[:akey].should eql("anothertest")
39
+ attribs['akey'].should be_nil
40
+ end
41
+ end
42
+
43
+ describe "#delete" do
44
+ it "should remove attribtue entry" do
45
+ @obj[:key] = 'value'
46
+ @obj.delete(:key)
47
+ @obj[:key].should be_nil
48
+ end
49
+ end
50
+
51
+ describe "#dup" do
52
+ it "should duplicate attributes" do
53
+ @obj[:key] = 'value'
54
+ @obj2 = @obj.dup
55
+ @obj2.send(:_attributes).object_id.should_not eql(@obj.send(:_attributes).object_id)
56
+ end
57
+ end
58
+
59
+ describe "#clone" do
60
+ it "should clone attributes" do
61
+ @obj[:key] = 'value'
62
+ @obj2 = @obj.clone
63
+ @obj2.send(:_attributes).object_id.should_not eql(@obj.send(:_attributes).object_id)
64
+ end
65
+ end
66
+
67
+
68
+ describe "#inspect" do
69
+
70
+ it "should provide something useful" do
71
+ @obj[:key1] = 'value1'
72
+ @obj[:key2] = 'value2'
73
+ @obj.inspect.should match(/#<.+ key1: "value1", key2: "value2">/)
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashme do
4
+
5
+ before :each do
6
+ @model = Class.new do
7
+ include Hashme
8
+ property :name, String
9
+ end
10
+ end
11
+
12
+ describe '.build' do
13
+ it "should create a Model and give a block to build it" do
14
+ @model.should_receive(:call_in_block)
15
+ @model.build do |model|
16
+ @model.call_in_block
17
+ model.should be_kind_of(@model)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "#initialize" do
23
+
24
+ it "should accept nil" do
25
+ expect {
26
+ @obj = @model.new
27
+ }.to_not raise_error
28
+ end
29
+
30
+ it "should accept and set attributes" do
31
+ @obj = @model.new(:name => "Sam")
32
+ @obj.name.should eql("Sam")
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashme::CastedArray do
4
+
5
+ let :owner do
6
+ double()
7
+ end
8
+
9
+ let :submodel do
10
+ Class.new do
11
+ include Hashme
12
+ property :name, String
13
+ end
14
+ end
15
+
16
+ describe "#initialize" do
17
+ before :each do
18
+ @prop = Hashme::Property.new(:name, String)
19
+ @obj = Hashme::CastedArray.new(owner, @prop, ['test'])
20
+ end
21
+
22
+ it "should prepare array" do
23
+ @obj.length.should eql(1)
24
+ end
25
+
26
+ it "should set owner and property" do
27
+ @obj.casted_by.should eql(owner)
28
+ @obj.casted_by_property.should eql(@prop)
29
+ end
30
+
31
+ it "should instantiate and cast each value" do
32
+ @obj.first.should eql("test")
33
+ @obj.first.class.should eql(String)
34
+ end
35
+ end
36
+
37
+ describe "adding to array" do
38
+
39
+ before :each do
40
+ @prop = Hashme::Property.new(:item, submodel)
41
+ @obj = Hashme::CastedArray.new(owner, @prop, [{:name => 'test'}])
42
+ end
43
+
44
+ it "should cast new items" do
45
+ @obj << {:name => 'test2'}
46
+ @obj.last.class.should eql(submodel)
47
+ @obj.first.name.should eql('test')
48
+ @obj.last.name.should eql('test2')
49
+
50
+ @obj.last.casted_by.should eql(owner)
51
+ @obj.last.casted_by_property.should eql(@prop)
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashme::Properties do
4
+
5
+ before :all do
6
+ @aux_model = Class.new do
7
+ include Hashme
8
+ property :age, Fixnum
9
+ end
10
+ Kernel.const_set("Aux", @aux_model)
11
+ end
12
+
13
+ before :each do
14
+ @model = Class.new do
15
+ include Hashme
16
+ property :name, String
17
+ end
18
+
19
+ @obj = @model.new
20
+ end
21
+
22
+
23
+ describe "#get_attribute" do
24
+ it "should provide object in model" do
25
+ @obj[:key1] = 'value'
26
+ @obj.get_attribute(:key1).should eql('value')
27
+ end
28
+ end
29
+
30
+ describe "#set_attribute" do
31
+ it "should be posible to set attribute not defined as property" do
32
+ @obj.set_attribute('key1', 'value1')
33
+ @obj.set_attribute(:key2, 'value2')
34
+ @obj[:key1].should eql('value1')
35
+ @obj[:key2].should eql('value2')
36
+ end
37
+
38
+ it "should set and cast attribute with property" do
39
+ property = @model.send(:properties)[:name]
40
+ name = "Fred Flinstone"
41
+ property.should_receive(:cast).with(@obj, name).and_return(name)
42
+ @obj.set_attribute(:name, name)
43
+ @obj[:name].should eql(name)
44
+ end
45
+ end
46
+
47
+ describe ".properties" do
48
+
49
+ it "should be instantiated after property set" do
50
+ @model.properties.should_not be_nil
51
+ @model.properties.class.should eql(Hash)
52
+ end
53
+
54
+ it "should be null if no properties" do
55
+ model = Class.new do
56
+ include Hashme
57
+ end
58
+ model.properties.should be_nil
59
+ end
60
+
61
+ end
62
+
63
+ describe ".property" do
64
+
65
+ it "should fail if no type is defined" do
66
+ @model.properties.length.should eql(1)
67
+ expect {
68
+ @model.property :foobar
69
+ }.to raise_error(ArgumentError)
70
+ @model.properties.length.should eql(1)
71
+ end
72
+
73
+ it "should create a new property with helper methods" do
74
+ @model.properties.length.should eql(1)
75
+ @model.property :desc, String
76
+ @model.properties.length.should eql(2)
77
+
78
+ prop = @model.properties[:desc]
79
+ prop.class.should eql(Hashme::Property)
80
+
81
+ @obj.should respond_to(:desc)
82
+ @obj.should respond_to(:desc=)
83
+
84
+ @obj.desc = "test"
85
+ @obj.desc.should eql("test")
86
+ end
87
+
88
+ it "should return nil on property with no default" do
89
+ @model.property :nickname, String
90
+ @obj.nickname.should be_nil
91
+ end
92
+
93
+ it "should create helper method with support for default values" do
94
+ @model.property :name, String, :default => "Sam"
95
+ @obj.name.should eql("Sam")
96
+ end
97
+
98
+ end
99
+
100
+
101
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashme::Property do
4
+
5
+ let :owner do
6
+ double()
7
+ end
8
+
9
+ let :klass do
10
+ Hashme::Property
11
+ end
12
+
13
+ let :submodel do
14
+ Class.new do
15
+ include Hashme
16
+ property :name, String
17
+ end
18
+ end
19
+
20
+ describe "#initialize" do
21
+
22
+ it "should copy name and type" do
23
+ prop = klass.new("name", String)
24
+ prop.name.should eql(:name)
25
+ prop.type.should eql(String)
26
+ prop.use_casted_array?.should be_false
27
+ end
28
+
29
+ it "should convert Array to CastedArray type" do
30
+ prop = klass.new("names", [String])
31
+ prop.name.should eql(:names)
32
+ prop.type.should eql(String)
33
+ prop.use_casted_array?.should be_true
34
+ end
35
+
36
+ it "should accept a default option" do
37
+ prop = klass.new(:name, String, :default => "Freddo")
38
+ prop.default.should eql("Freddo")
39
+ end
40
+
41
+ end
42
+
43
+ describe "#to_s" do
44
+ it "should use property's name" do
45
+ prop = klass.new(:name, String)
46
+ prop.to_s.should eql("name")
47
+ end
48
+ end
49
+
50
+ describe "#to_sym" do
51
+ it "should return the name" do
52
+ prop = klass.new(:name, String)
53
+ prop.to_sym.should eql (:name)
54
+ end
55
+ end
56
+
57
+ describe "#cast" do
58
+ context "without an array" do
59
+ it "should build a new object" do
60
+ prop = klass.new(:date, Time)
61
+ obj = prop.cast(owner, "2013-06-02T12:00:00")
62
+ obj.class.should eql(Time)
63
+ obj.should eql(Time.new("2013-06-02T12:00:00"))
64
+ end
65
+
66
+ it "should assign casted by and property" do
67
+ prop = klass.new(:item, submodel)
68
+ obj = prop.cast(owner, {:name => 'test'})
69
+ obj.casted_by.should eql(owner)
70
+ obj.casted_by_property.should eql(prop)
71
+ end
72
+ end
73
+
74
+ context "with an array" do
75
+ it "should convert regular array to casted array" do
76
+ prop = klass.new(:dates, [Time])
77
+ obj = prop.cast(owner, ["2013-06-02T12:00:00"])
78
+ obj.class.should eql(Hashme::CastedArray)
79
+ obj.first.class.should eql(Time)
80
+ end
81
+ it "should handle complex objects" do
82
+ prop = klass.new(:items, [submodel])
83
+ obj = prop.cast(owner, [{:name => 'test'}])
84
+ obj.class.should eql(Hashme::CastedArray)
85
+ obj.first.class.should eql(submodel)
86
+ obj.first.name.should eql('test')
87
+ end
88
+ end
89
+ end
90
+
91
+
92
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'rspec'
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ require 'hashme'
8
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hashme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sam Lown
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Modeling with Hashes made easy.
70
+ email:
71
+ - me@samlown.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - hashme.gemspec
82
+ - lib/hashme.rb
83
+ - lib/hashme/attributes.rb
84
+ - lib/hashme/castable.rb
85
+ - lib/hashme/casted_array.rb
86
+ - lib/hashme/properties.rb
87
+ - lib/hashme/property.rb
88
+ - lib/hashme/version.rb
89
+ - spec/hashme/attributes_spec.rb
90
+ - spec/hashme/base_spec.rb
91
+ - spec/hashme/casted_array_spec.rb
92
+ - spec/hashme/properties_spec.rb
93
+ - spec/hashme/property_spec.rb
94
+ - spec/spec_helper.rb
95
+ homepage: ''
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.0.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Easily define simple models that can be easily serialized and de-serialized.
119
+ test_files:
120
+ - spec/hashme/attributes_spec.rb
121
+ - spec/hashme/base_spec.rb
122
+ - spec/hashme/casted_array_spec.rb
123
+ - spec/hashme/properties_spec.rb
124
+ - spec/hashme/property_spec.rb
125
+ - spec/spec_helper.rb