hashme 0.1.0

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.
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