diff --git a/README.md b/README.md index 7f08fb66..cf82374c 100644 --- a/README.md +++ b/README.md @@ -542,6 +542,33 @@ Blog.attribute_set[:posts].member_type.primitive # => Post Post.attribute_set[:blog].type.primitive # => Blog ``` +Virtus::Lite +------------ + +Virtus::Lite is a drop-in replacement for Virtus.model that supports the core +feature set of Virtus (type coercion, custom coercion, and default values), +while delivering 10x the speed. Many apps will be able to simply replace +`include Virtus.model` with `include Virtus::Lite` to enjoy this performance +boost. + +``` +Comparison: +FastAttributes: without values : 2326399.8 i/s +Virtus::Lite: without values : 319304.0 i/s - 7.29x slower +FastAttributes: integer values for integer attributes: 82969.3 i/s - 28.04x slower +FastAttributes: string values for integer attributes : 64758.7 i/s - 35.92x slower +Virtus::Lite: string values for integer attributes : 37270.1 i/s - 62.42x slower +Virtus::Lite: integer values for integer attributes : 36577.8 i/s - 63.60x slower +Virtus: integer values for integer attributes : 21857.4 i/s - 106.44x slower +Attrio: integer values for integer attributes : 11362.2 i/s - 204.75x slower +Virtus: without values : 9551.8 i/s - 243.56x slower +Attrio: string values for integer attributes : 9048.5 i/s - 257.10x slower +Attrio: without values : 6876.1 i/s - 338.33x slower +Virtus: string values for integer attributes : 3197.6 i/s - 727.55x slower +``` + +Adapted from the [fast_attributes benchmark code.](https://github.com/applift/fast_attributes/blob/master/benchmarks/comparison.rb) + Ruby version support -------------------- diff --git a/lib/virtus.rb b/lib/virtus.rb index 9e68ce7c..0c1fce0c 100644 --- a/lib/virtus.rb +++ b/lib/virtus.rb @@ -284,3 +284,5 @@ def self.warn(msg) require 'virtus/attribute/collection' require 'virtus/attribute/hash' require 'virtus/attribute/embedded_value' + +require 'virtus/lite' diff --git a/lib/virtus/lite.rb b/lib/virtus/lite.rb new file mode 100644 index 00000000..7b1bc491 --- /dev/null +++ b/lib/virtus/lite.rb @@ -0,0 +1,123 @@ +module Virtus + module Lite + + class Boolean; end + + module ClassMethods + + attr_reader :attributes + attr_reader :set_attributes + + def attribute( name, type = nil, options = {} ) + @attributes ||= [] + @attributes << name unless @attributes.include? name + define_method( "#{ name }=") do |value| + @set_attributes ||= [] + @set_attributes << name + instance_variable_set "@#{ name }", value + end + define_method( name ) do + value = instance_variable_get "@#{ name }" + coercer = options[ :coercer ] + default = options[ :default ] + if coercer + coercer.call value + elsif value.nil? and not default.nil? and default.is_a? Symbol and respond_to? default + send default + else + if type.is_a? Array + if value.nil? + [] + elsif value.is_a? Array + value.map { |v| determine_value name, v, type.first, options } + else + determine_value name, value, type.first, options + end + else + determine_value name, value, type, options + end + end + end + # private :"#{ name }" if options[ :reader ] == :private + # private :"#{ name }=" if options[ :writer ] == :private + self + end + end + + def self.included( base ) + base.extend ClassMethods + end + + def attributes + Hash[ self.class.attributes.map { |v| [ v, send( v ) ] } ] || {} + end + + def []( key ) + send( key ) if self.class.attributes.include? key + end + + private + + def determine_value( name, value, type, options ) + default = options[ :default ] + if value.nil? and not default.nil? + value = default + elsif type and not value.is_a? type + if not value.nil? and @set_attributes.include? name + if value.is_a? Hash and not type.is_a? Hash + value = type.new value + else + value = convert value, type + end + end + end + value + end + + def initialize( params = {} ) + unless params.nil? + params.each do |name, value| + self.send( :"#{name}=", value ) if respond_to? "#{ name }=" + end + end + self.class.send( :define_method, :to_hash ) do + Hash[ self.class.attributes.map { |attribute| [ attribute, send( attribute ) ] } ] + end + end + + def convert( value, type ) + case type.to_s + when 'String' + value.to_s + when 'Integer', 'Fixnum', 'Bignum' + if value.respond_to? :to_i + value.to_i + elsif value.is_a? TrueClass or value.is_a? FalseClass + value ? 1 : 0 + else + 0 + end + when 'Float' + if value.respond_to? :to_f + value.to_f + elsif value.is_a? TrueClass or value.is_a? FalseClass + value ? 1.0 : 0.0 + end + when 'Virtus::Attribute::Boolean', 'Virtus::Lite::Boolean' + if value.nil? + false + elsif value.is_a? String + value != '' + elsif value.is_a? Integer + value != 0 + elsif value.is_a? TrueClass or value.is_a? FalseClass + value + elsif value.is_a? Float + value != 0.0 + else + true + end + end + end + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/array_integer_spec.rb b/spec/unit/virtus/lite/array_integer_spec.rb new file mode 100644 index 00000000..ac9afe58 --- /dev/null +++ b/spec/unit/virtus/lite/array_integer_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +class PlainArrayIntegerTest + include Virtus::Lite + attribute :fish, Array[Integer] +end + +describe PlainArrayIntegerTest do + before do + @test = PlainArrayIntegerTest.new + end + + it 'returns array of integers when set to array of strings' do + @test.fish = [ 'red', 'blue' ] + expect( @test.fish ).to eq( [ 0, 0 ] ) + end + it 'returns array of integers when set to array of integers' do + @test.fish = [ 1, 2 ] + expect( @test.fish ).to eq( [ 1, 2 ] ) + end + it 'returns array of integers when set to array of booleans' do + @test.fish = [ true, false ] + expect( @test.fish ).to eq( [ 1, 0 ] ) + end + it 'returns array of integers when set to array of floats' do + @test.fish = [ 7.6, 23.5 ] + expect( @test.fish ).to eq( [ 7, 23 ] ) + end + it 'returns array of integers when set to a mixed array' do + @test.fish = [ 'red', 42, false, 34.5, Integer ] + expect( @test.fish ).to eq( [ 0, 42, 0, 34, 0 ] ) + end +end diff --git a/spec/unit/virtus/lite/array_integer_spec.rb-e b/spec/unit/virtus/lite/array_integer_spec.rb-e new file mode 100644 index 00000000..35fcd19c --- /dev/null +++ b/spec/unit/virtus/lite/array_integer_spec.rb-e @@ -0,0 +1,33 @@ +require 'spec_helper' + +class PlainArrayIntegerTest + include Subvirtus + attribute :fish, Array[Integer] +end + +describe PlainArrayIntegerTest do + before do + @test = PlainArrayIntegerTest.new + end + + it 'returns array of integers when set to array of strings' do + @test.fish = [ 'red', 'blue' ] + expect( @test.fish ).to eq( [ 0, 0 ] ) + end + it 'returns array of integers when set to array of integers' do + @test.fish = [ 1, 2 ] + expect( @test.fish ).to eq( [ 1, 2 ] ) + end + it 'returns array of integers when set to array of booleans' do + @test.fish = [ true, false ] + expect( @test.fish ).to eq( [ 1, 0 ] ) + end + it 'returns array of integers when set to array of floats' do + @test.fish = [ 7.6, 23.5 ] + expect( @test.fish ).to eq( [ 7, 23 ] ) + end + it 'returns array of integers when set to a mixed array' do + @test.fish = [ 'red', 42, false, 34.5, Integer ] + expect( @test.fish ).to eq( [ 0, 42, 0, 34, 0 ] ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/array_string_spec.rb b/spec/unit/virtus/lite/array_string_spec.rb new file mode 100644 index 00000000..52d0c697 --- /dev/null +++ b/spec/unit/virtus/lite/array_string_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +class PlainArrayStringTest + include Virtus::Lite + attribute :fish, Array[String] +end + +describe PlainArrayStringTest do + before do + @test = PlainArrayStringTest.new + end + + it 'returns array of strings when set to array of strings' do + @test.fish = [ 'red', 'blue' ] + expect( @test.fish ).to eq( [ 'red', 'blue' ] ) + end + it 'returns array of strings when set to array of integers' do + @test.fish = [ 1, 2 ] + expect( @test.fish ).to eq( [ '1', '2' ] ) + end + it 'returns array of strings when set to array of booleans' do + @test.fish = [ true, false ] + expect( @test.fish ).to eq( [ 'true', 'false' ] ) + end + it 'returns array of strings when set to array of floats' do + @test.fish = [ 7.6, 23.5 ] + expect( @test.fish ).to eq( [ '7.6', '23.5' ] ) + end + it 'returns array of strings when set to a mixed array' do + @test.fish = [ 'red', 42, false, 34.5, String ] + expect( @test.fish ).to eq( [ 'red', '42', 'false', '34.5', 'String' ] ) + end +end diff --git a/spec/unit/virtus/lite/array_string_spec.rb-e b/spec/unit/virtus/lite/array_string_spec.rb-e new file mode 100644 index 00000000..c6b5d898 --- /dev/null +++ b/spec/unit/virtus/lite/array_string_spec.rb-e @@ -0,0 +1,33 @@ +require 'spec_helper' + +class PlainArrayStringTest + include Subvirtus + attribute :fish, Array[String] +end + +describe PlainArrayStringTest do + before do + @test = PlainArrayStringTest.new + end + + it 'returns array of strings when set to array of strings' do + @test.fish = [ 'red', 'blue' ] + expect( @test.fish ).to eq( [ 'red', 'blue' ] ) + end + it 'returns array of strings when set to array of integers' do + @test.fish = [ 1, 2 ] + expect( @test.fish ).to eq( [ '1', '2' ] ) + end + it 'returns array of strings when set to array of booleans' do + @test.fish = [ true, false ] + expect( @test.fish ).to eq( [ 'true', 'false' ] ) + end + it 'returns array of strings when set to array of floats' do + @test.fish = [ 7.6, 23.5 ] + expect( @test.fish ).to eq( [ '7.6', '23.5' ] ) + end + it 'returns array of strings when set to a mixed array' do + @test.fish = [ 'red', 42, false, 34.5, String ] + expect( @test.fish ).to eq( [ 'red', '42', 'false', '34.5', 'String' ] ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/attribute_spec.rb b/spec/unit/virtus/lite/attribute_spec.rb new file mode 100644 index 00000000..549f56c5 --- /dev/null +++ b/spec/unit/virtus/lite/attribute_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'include Virtus::Lite' do + + let :model do + Class.new do + include Virtus::Lite + end + end + + it 'responds to #attribute' do + expect( model ).to respond_to( :attribute ) + end + + it 'responds to #attributes' do + expect( model ).to respond_to( :attributes ) + end + + it 'responds to #set_attributes' do + expect( model ).to respond_to( :set_attributes ) + end +end diff --git a/spec/unit/virtus/lite/attribute_spec.rb-e b/spec/unit/virtus/lite/attribute_spec.rb-e new file mode 100644 index 00000000..1dcd2020 --- /dev/null +++ b/spec/unit/virtus/lite/attribute_spec.rb-e @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'include Subvirtus' do + + let :model do + Class.new do + include Subvirtus + end + end + + it 'responds to #attribute' do + expect( model ).to respond_to( :attribute ) + end + + it 'responds to #attributes' do + expect( model ).to respond_to( :attributes ) + end + + it 'responds to #set_attributes' do + expect( model ).to respond_to( :set_attributes ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/bignum_spec.rb b/spec/unit/virtus/lite/bignum_spec.rb new file mode 100644 index 00000000..ed310c36 --- /dev/null +++ b/spec/unit/virtus/lite/bignum_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Virtus::Lite + attribute :age, Bignum +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Virtus::Lite + attribute :age, Bignum, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end diff --git a/spec/unit/virtus/lite/bignum_spec.rb-e b/spec/unit/virtus/lite/bignum_spec.rb-e new file mode 100644 index 00000000..ba8f8e3b --- /dev/null +++ b/spec/unit/virtus/lite/bignum_spec.rb-e @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Subvirtus + attribute :age, Bignum +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Subvirtus + attribute :age, Bignum, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/boolean_spec.rb b/spec/unit/virtus/lite/boolean_spec.rb new file mode 100644 index 00000000..41fd83e2 --- /dev/null +++ b/spec/unit/virtus/lite/boolean_spec.rb @@ -0,0 +1,154 @@ +require 'spec_helper' + +class PlainBooleanTest + include Virtus::Lite + attribute :here, Boolean +end + +describe PlainBooleanTest do + before do + @test = PlainBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns nil when passed a nil with no default value' do + @test.here = nil + expect( @test.here ).to eq( nil ) + end + it 'returns nil when not passed anything' do + expect( @test.here ).to eq( nil ) + end +end + +class TrueBooleanTest + include Virtus::Lite + attribute :here, Boolean, default: true +end + +describe TrueBooleanTest do + before do + @test = TrueBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns true if passed nil with a default value of true' do + @test.here = nil + expect( @test.here ).to eq( true ) + end + it 'returns true when not passed anything with a default value of true' do + expect( @test.here ).to eq( true ) + end +end + +class FalseBooleanTest + include Virtus::Lite + attribute :here, Boolean, default: false +end + +describe FalseBooleanTest do + before do + @test = FalseBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns false if passed nil with a default value of false' do + @test.here = nil + expect( @test.here ).to eq( false ) + end + it 'returns false when not passed anything with a default value of false' do + expect( @test.here ).to eq( false ) + end +end diff --git a/spec/unit/virtus/lite/boolean_spec.rb-e b/spec/unit/virtus/lite/boolean_spec.rb-e new file mode 100644 index 00000000..7bb82ed8 --- /dev/null +++ b/spec/unit/virtus/lite/boolean_spec.rb-e @@ -0,0 +1,154 @@ +require 'spec_helper' + +class PlainBooleanTest + include Subvirtus + attribute :here, Boolean +end + +describe PlainBooleanTest do + before do + @test = PlainBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns nil when passed a nil with no default value' do + @test.here = nil + expect( @test.here ).to eq( nil ) + end + it 'returns nil when not passed anything' do + expect( @test.here ).to eq( nil ) + end +end + +class TrueBooleanTest + include Subvirtus + attribute :here, Boolean, default: true +end + +describe TrueBooleanTest do + before do + @test = TrueBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns true if passed nil with a default value of true' do + @test.here = nil + expect( @test.here ).to eq( true ) + end + it 'returns true when not passed anything with a default value of true' do + expect( @test.here ).to eq( true ) + end +end + +class FalseBooleanTest + include Subvirtus + attribute :here, Boolean, default: false +end + +describe FalseBooleanTest do + before do + @test = FalseBooleanTest.new + end + + it 'returns true when set to true' do + @test.here = false + expect( @test.here ).to eq( false ) + end + it 'returns false when set to false' do + @test.here = true + expect( @test.here ).to eq( true ) + end + it 'returns true when passed a truthy string' do + @test.here = 'anything not blank' + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey string' do + @test.here = '' + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy integer' do + @test.here = 42 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey integer' do + @test.here = 0 + expect( @test.here ).to eq( false ) + end + it 'returns true when passed a truthy float' do + @test.here = 67.89 + expect( @test.here ).to eq( true ) + end + it 'returns false when passed a falsey float' do + @test.here = 0.0 + expect( @test.here ).to eq( false ) + end + it 'returns false if passed nil with a default value of false' do + @test.here = nil + expect( @test.here ).to eq( false ) + end + it 'returns false when not passed anything with a default value of false' do + expect( @test.here ).to eq( false ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/coercer_spec.rb b/spec/unit/virtus/lite/coercer_spec.rb new file mode 100644 index 00000000..f077fc41 --- /dev/null +++ b/spec/unit/virtus/lite/coercer_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +class BooleanWriter + def self.call( value ) + true + end +end +class HashWriter + def self.call( value ) + { a: 1, b: 2, z: 26 } + end +end +class BooleanAsIntegerWriter + def self.call( value ) + 1 + end +end + +class CoercerTest + include Virtus::Lite + attribute :here, Boolean, coercer: BooleanWriter + attribute :abcs, Hash, coercer: HashWriter + attribute :number, Boolean, coercer: BooleanAsIntegerWriter +end + +describe CoercerTest do + before do + @test = CoercerTest.new + end + + it 'returns true when coercer sets to true' do + expect( @test.here ).to eq( true ) + end + + it 'returns the return value of a coercer' do + expect( @test.abcs ).to eq( { a: 1, b: 2, z: 26 } ) + end + + it 'does not convert a value returned by a coercer' do + expect( @test.number ).to eq( 1 ) + end +end diff --git a/spec/unit/virtus/lite/coercer_spec.rb-e b/spec/unit/virtus/lite/coercer_spec.rb-e new file mode 100644 index 00000000..48a8427a --- /dev/null +++ b/spec/unit/virtus/lite/coercer_spec.rb-e @@ -0,0 +1,42 @@ +require 'spec_helper' + +class BooleanWriter + def self.call( value ) + true + end +end +class HashWriter + def self.call( value ) + { a: 1, b: 2, z: 26 } + end +end +class BooleanAsIntegerWriter + def self.call( value ) + 1 + end +end + +class CoercerTest + include Subvirtus + attribute :here, Boolean, coercer: BooleanWriter + attribute :abcs, Hash, coercer: HashWriter + attribute :number, Boolean, coercer: BooleanAsIntegerWriter +end + +describe CoercerTest do + before do + @test = CoercerTest.new + end + + it 'returns true when coercer sets to true' do + expect( @test.here ).to eq( true ) + end + + it 'returns the return value of a coercer' do + expect( @test.abcs ).to eq( { a: 1, b: 2, z: 26 } ) + end + + it 'does not convert a value returned by a coercer' do + expect( @test.number ).to eq( 1 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/fixnum_spec.rb b/spec/unit/virtus/lite/fixnum_spec.rb new file mode 100644 index 00000000..84d995cd --- /dev/null +++ b/spec/unit/virtus/lite/fixnum_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Virtus::Lite + attribute :age, Fixnum +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns a integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns a integer when given a integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Virtus::Lite + attribute :age, Fixnum, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns a integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns a integer when given a integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns a integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end diff --git a/spec/unit/virtus/lite/fixnum_spec.rb-e b/spec/unit/virtus/lite/fixnum_spec.rb-e new file mode 100644 index 00000000..e6246935 --- /dev/null +++ b/spec/unit/virtus/lite/fixnum_spec.rb-e @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Subvirtus + attribute :age, Fixnum +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns a integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns a integer when given a integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Subvirtus + attribute :age, Fixnum, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns a integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns a integer when given a integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns a integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns a integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/float_spec.rb b/spec/unit/virtus/lite/float_spec.rb new file mode 100644 index 00000000..8576239a --- /dev/null +++ b/spec/unit/virtus/lite/float_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainFloatTest + include Virtus::Lite + attribute :cash, Float +end + +describe PlainFloatTest do + before do + @test = PlainFloatTest.new + end + + it 'returns a float value given' do + @test.cash = 11.89 + expect( @test.cash ).to eq( 11.89 ) + end + it 'returns a float when given a float' do + @test.cash = 87.2 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float when given a string' do + @test.cash = "42.5" + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given float in a string' do + @test.cash = "42.5" + expect( @test.cash ).to eq( 42.5 ) + end + it 'returns a float when given an integer' do + @test.cash = 42 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given integer' do + @test.cash = 42 + expect( @test.cash ).to eq( 42.0 ) + end + it 'returns a float when given a boolean' do + @test.cash = true + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a 0.0 when given a false' do + @test.cash = false + expect( @test.cash ).to eq( 0.0 ) + end + it 'returns a 1.0 when given a true' do + @test.cash = true + expect( @test.cash ).to eq( 1.0 ) + end + it 'does not return a float when given a nil' do + @test.cash = nil + expect( @test.cash.is_a? Float ).to be_falsey + end + it 'returns nil when given a nil' do + @test.cash = nil + expect( @test.cash ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.cash ).to eq( nil ) + end +end + +class FloatTestWithDefault + include Virtus::Lite + attribute :cash, Float, default: 9.57 +end + +describe FloatTestWithDefault do + before do + @test = FloatTestWithDefault.new + end + + it 'returns a float value given' do + @test.cash = 11.89 + expect( @test.cash ).to eq( 11.89 ) + end + it 'returns a float when given a float' do + @test.cash = 87.2 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float when given a string' do + @test.cash = "42.5" + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given float in a string' do + @test.cash = "42.5" + expect( @test.cash ).to eq( 42.5 ) + end + it 'returns a float when given an integer' do + @test.cash = 42 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given integer' do + @test.cash = 42 + expect( @test.cash ).to eq( 42.0 ) + end + it 'returns a float when given a boolean' do + @test.cash = true + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a 0.0 when given a false' do + @test.cash = false + expect( @test.cash ).to eq( 0.0 ) + end + it 'returns a 1.0 when given a true' do + @test.cash = true + expect( @test.cash ).to eq( 1.0 ) + end + it 'returns a float when given a nil' do + @test.cash = nil + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns the default when given a nil' do + @test.cash = nil + expect( @test.cash ).to eq( 9.57 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.cash ).to eq( 9.57 ) + end +end diff --git a/spec/unit/virtus/lite/float_spec.rb-e b/spec/unit/virtus/lite/float_spec.rb-e new file mode 100644 index 00000000..93e70ea7 --- /dev/null +++ b/spec/unit/virtus/lite/float_spec.rb-e @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainFloatTest + include Subvirtus + attribute :cash, Float +end + +describe PlainFloatTest do + before do + @test = PlainFloatTest.new + end + + it 'returns a float value given' do + @test.cash = 11.89 + expect( @test.cash ).to eq( 11.89 ) + end + it 'returns a float when given a float' do + @test.cash = 87.2 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float when given a string' do + @test.cash = "42.5" + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given float in a string' do + @test.cash = "42.5" + expect( @test.cash ).to eq( 42.5 ) + end + it 'returns a float when given an integer' do + @test.cash = 42 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given integer' do + @test.cash = 42 + expect( @test.cash ).to eq( 42.0 ) + end + it 'returns a float when given a boolean' do + @test.cash = true + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a 0.0 when given a false' do + @test.cash = false + expect( @test.cash ).to eq( 0.0 ) + end + it 'returns a 1.0 when given a true' do + @test.cash = true + expect( @test.cash ).to eq( 1.0 ) + end + it 'does not return a float when given a nil' do + @test.cash = nil + expect( @test.cash.is_a? Float ).to be_falsey + end + it 'returns nil when given a nil' do + @test.cash = nil + expect( @test.cash ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.cash ).to eq( nil ) + end +end + +class FloatTestWithDefault + include Subvirtus + attribute :cash, Float, default: 9.57 +end + +describe FloatTestWithDefault do + before do + @test = FloatTestWithDefault.new + end + + it 'returns a float value given' do + @test.cash = 11.89 + expect( @test.cash ).to eq( 11.89 ) + end + it 'returns a float when given a float' do + @test.cash = 87.2 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float when given a string' do + @test.cash = "42.5" + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given float in a string' do + @test.cash = "42.5" + expect( @test.cash ).to eq( 42.5 ) + end + it 'returns a float when given an integer' do + @test.cash = 42 + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a float representive of a given integer' do + @test.cash = 42 + expect( @test.cash ).to eq( 42.0 ) + end + it 'returns a float when given a boolean' do + @test.cash = true + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns a 0.0 when given a false' do + @test.cash = false + expect( @test.cash ).to eq( 0.0 ) + end + it 'returns a 1.0 when given a true' do + @test.cash = true + expect( @test.cash ).to eq( 1.0 ) + end + it 'returns a float when given a nil' do + @test.cash = nil + expect( @test.cash.is_a? Float ).to be_truthy + end + it 'returns the default when given a nil' do + @test.cash = nil + expect( @test.cash ).to eq( 9.57 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.cash ).to eq( 9.57 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/initialize_more_spec.rb b/spec/unit/virtus/lite/initialize_more_spec.rb new file mode 100644 index 00000000..201d79ae --- /dev/null +++ b/spec/unit/virtus/lite/initialize_more_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'sending a Hash to new' do + + class InitializeTest + include Virtus::Lite + + attribute :string_1, String + attribute :integer_1, Integer + attribute :boolean_1, Boolean + attribute :float_1, Float + attribute :fixnum_1, Fixnum + attribute :bignum_1, Bignum + + attribute :string_2, String + attribute :integer_2, Integer + attribute :boolean_2, Boolean + attribute :float_2, Float + attribute :fixnum_2, Fixnum + attribute :bignum_2, Bignum + end + + let( :test ) { InitializeTest.new( { string_1: 'subvirtus', + integer_1: 12, + boolean_1: true, + float_1: 13.45, + fixnum_1: 14, + bignum_1: 9999999999899999999 * 9999999999899999999, + + string_2: 'david', + integer_2: 16, + boolean_2: false, + float_2: 17.45, + fixnum_2: 18, + bignum_2: 9999999999999999999 * 9999999999999999999 } ) } + + { + string_1: { type: String, value: 'subvirtus' }, + integer_1: { type: Integer, value: 12 }, + boolean_1: { type: TrueClass, value: true }, + float_1: { type: Float, value: 13.45 }, + fixnum_1: { type: Fixnum, value: 14 }, + bignum_1: { type: Bignum, value: 9999999999899999999 * 9999999999899999999 }, + + string_2: { type: String, value: 'david' }, + integer_2: { type: Integer, value: 16 }, + boolean_2: { type: FalseClass, value: false }, + float_2: { type: Float, value: 17.45 }, + fixnum_2: { type: Fixnum, value: 18 }, + bignum_2: { type: Bignum, value: 9999999999999999999 * 9999999999999999999 } + }.each do |attr, value| + it "responds to ##{ attr }" do + expect( test ).to respond_to( attr ) + end + it "responds to ##{ attr }=" do + expect( test ).to respond_to( "#{ attr }=" ) + end + it "has the right value for ##{ attr }" do + expect( test.send attr ).to eq( value[ :value ] ) + end + it "has the right type for ##{ attr }" do + expect( test.send( attr ).is_a? value[ :type ] ).to be_truthy + end + end +end diff --git a/spec/unit/virtus/lite/initialize_more_spec.rb-e b/spec/unit/virtus/lite/initialize_more_spec.rb-e new file mode 100644 index 00000000..153275b6 --- /dev/null +++ b/spec/unit/virtus/lite/initialize_more_spec.rb-e @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'sending a Hash to new' do + + class InitializeTest + include Subvirtus + + attribute :string_1, String + attribute :integer_1, Integer + attribute :boolean_1, Boolean + attribute :float_1, Float + attribute :fixnum_1, Fixnum + attribute :bignum_1, Bignum + + attribute :string_2, String + attribute :integer_2, Integer + attribute :boolean_2, Boolean + attribute :float_2, Float + attribute :fixnum_2, Fixnum + attribute :bignum_2, Bignum + end + + let( :test ) { InitializeTest.new( { string_1: 'subvirtus', + integer_1: 12, + boolean_1: true, + float_1: 13.45, + fixnum_1: 14, + bignum_1: 9999999999899999999 * 9999999999899999999, + + string_2: 'david', + integer_2: 16, + boolean_2: false, + float_2: 17.45, + fixnum_2: 18, + bignum_2: 9999999999999999999 * 9999999999999999999 } ) } + + { + string_1: { type: String, value: 'subvirtus' }, + integer_1: { type: Integer, value: 12 }, + boolean_1: { type: TrueClass, value: true }, + float_1: { type: Float, value: 13.45 }, + fixnum_1: { type: Fixnum, value: 14 }, + bignum_1: { type: Bignum, value: 9999999999899999999 * 9999999999899999999 }, + + string_2: { type: String, value: 'david' }, + integer_2: { type: Integer, value: 16 }, + boolean_2: { type: FalseClass, value: false }, + float_2: { type: Float, value: 17.45 }, + fixnum_2: { type: Fixnum, value: 18 }, + bignum_2: { type: Bignum, value: 9999999999999999999 * 9999999999999999999 } + }.each do |attr, value| + it "responds to ##{ attr }" do + expect( test ).to respond_to( attr ) + end + it "responds to ##{ attr }=" do + expect( test ).to respond_to( "#{ attr }=" ) + end + it "has the right value for ##{ attr }" do + expect( test.send attr ).to eq( value[ :value ] ) + end + it "has the right type for ##{ attr }" do + expect( test.send( attr ).is_a? value[ :type ] ).to be_truthy + end + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/initialize_spec.rb b/spec/unit/virtus/lite/initialize_spec.rb new file mode 100644 index 00000000..f00951f7 --- /dev/null +++ b/spec/unit/virtus/lite/initialize_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +class InitializerTest + include Virtus::Lite + attribute :here, Boolean, default: true + attribute :name, String, default: 'subvirtus' + attribute :cash, Float, default: 9.57 + attribute :age, Integer, default: 12 + attribute :home, String, default: 'Sweet Home' +end + +describe InitializerTest do + before do + @test = InitializerTest.new( { here: false, name: 'david', cash: 12.34, age: 21, random: 'abc' } ) + end + + it "has the correct boolean value from a passed in hash" do + expect( @test.here ).to eq( false ) + end + + it "has the correct string value from a passed in hash" do + expect( @test.name ).to eq( 'david' ) + end + + it "has the correct float value from a passed in hash" do + expect( @test.cash ).to eq( 12.34 ) + end + + it "has the correct integer value from a passed in hash" do + expect( @test.age ).to eq( 21 ) + end + + it "ignores a random value in a passed in hash" do + expect{ @test.random }.to raise_error + end + + it "still works for attributes not set in a passed in hash" do + expect( @test.home ).to eq( 'Sweet Home' ) + end + + it "returns a hash" do + expect( @test.to_hash ).to eq( { here: false, name: 'david', cash: 12.34, age: 21, home: 'Sweet Home' } ) + end +end diff --git a/spec/unit/virtus/lite/initialize_spec.rb-e b/spec/unit/virtus/lite/initialize_spec.rb-e new file mode 100644 index 00000000..6ad2c76d --- /dev/null +++ b/spec/unit/virtus/lite/initialize_spec.rb-e @@ -0,0 +1,44 @@ +require 'spec_helper' + +class InitializerTest + include Subvirtus + attribute :here, Boolean, default: true + attribute :name, String, default: 'subvirtus' + attribute :cash, Float, default: 9.57 + attribute :age, Integer, default: 12 + attribute :home, String, default: 'Sweet Home' +end + +describe InitializerTest do + before do + @test = InitializerTest.new( { here: false, name: 'david', cash: 12.34, age: 21, random: 'abc' } ) + end + + it "has the correct boolean value from a passed in hash" do + expect( @test.here ).to eq( false ) + end + + it "has the correct string value from a passed in hash" do + expect( @test.name ).to eq( 'david' ) + end + + it "has the correct float value from a passed in hash" do + expect( @test.cash ).to eq( 12.34 ) + end + + it "has the correct integer value from a passed in hash" do + expect( @test.age ).to eq( 21 ) + end + + it "ignores a random value in a passed in hash" do + expect{ @test.random }.to raise_error + end + + it "still works for attributes not set in a passed in hash" do + expect( @test.home ).to eq( 'Sweet Home' ) + end + + it "returns a hash" do + expect( @test.to_hash ).to eq( { here: false, name: 'david', cash: 12.34, age: 21, home: 'Sweet Home' } ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/integer_spec.rb b/spec/unit/virtus/lite/integer_spec.rb new file mode 100644 index 00000000..bc3ac112 --- /dev/null +++ b/spec/unit/virtus/lite/integer_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Virtus::Lite + attribute :age, Integer +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Virtus::Lite + attribute :age, Integer, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end diff --git a/spec/unit/virtus/lite/integer_spec.rb-e b/spec/unit/virtus/lite/integer_spec.rb-e new file mode 100644 index 00000000..d8db3d0b --- /dev/null +++ b/spec/unit/virtus/lite/integer_spec.rb-e @@ -0,0 +1,119 @@ +require 'spec_helper' + +class PlainIntegerTest + include Subvirtus + attribute :age, Integer +end + +describe PlainIntegerTest do + before do + @test = PlainIntegerTest.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'does not return an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_falsey + end + it 'returns nil when given a nil' do + @test.age = nil + expect( @test.age ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.age ).to eq( nil ) + end +end + +class IntegerTestWithDefault + include Subvirtus + attribute :age, Integer, default: 9 +end + +describe IntegerTestWithDefault do + before do + @test = IntegerTestWithDefault.new + end + + it 'returns an integer value given' do + @test.age = 11 + expect( @test.age ).to eq( 11 ) + end + it 'returns an integer when given an integer' do + @test.age = 87 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer when given a string' do + @test.age = "42" + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given integer in a string' do + @test.age = "42" + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given an float' do + @test.age = 42.7 + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns an integer representive of a given float' do + @test.age = 42.7 + expect( @test.age ).to eq( 42 ) + end + it 'returns an integer when given a boolean' do + @test.age = true + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns a 0 when given a false' do + @test.age = false + expect( @test.age ).to eq( 0 ) + end + it 'returns a 1 when given a true' do + @test.age = true + expect( @test.age ).to eq( 1 ) + end + it 'returns an integer when given a nil' do + @test.age = nil + expect( @test.age.is_a? Integer ).to be_truthy + end + it 'returns the default when given a nil' do + @test.age = nil + expect( @test.age ).to eq( 9 ) + end + it 'returns the default when nothing is passed in' do + expect( @test.age ).to eq( 9 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/multiples_spec.rb b/spec/unit/virtus/lite/multiples_spec.rb new file mode 100644 index 00000000..488d194a --- /dev/null +++ b/spec/unit/virtus/lite/multiples_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +class PlainMultiplesTest + include Virtus::Lite + attribute :name, String + attribute :age, Integer + attribute :here, Boolean + attribute :cash, Float +end + +describe PlainMultiplesTest do + before do + @test = PlainMultiplesTest.new + end + + it 'returns nil initial values for multiple attributes' do + expect( @test.name ).to eq( nil ) + expect( @test.age ).to eq( nil ) + expect( @test.here ).to eq( nil ) + expect( @test.cash ).to eq( nil ) + end + it 'returns separate values for multiple given attributes' do + @test.name = 'david' + @test.age = 42 + @test.here = true + @test.cash = 9.57 + + expect( @test.name ).to eq( 'david' ) + expect( @test.age ).to eq( 42 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.57 ) + end +end + +class MultiplesTestWithDefaults + include Virtus::Lite + attribute :name, String, default: 'subvirtus' + attribute :age, Integer, default: 43 + attribute :here, Boolean, default: true + attribute :cash, Float, default: 9.99 +end + +describe MultiplesTestWithDefaults do + before do + @test = MultiplesTestWithDefaults.new + end + + it 'returns separate initial values for multiple attributes' do + expect( @test.name ).to eq( 'subvirtus' ) + expect( @test.age ).to eq( 43 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.99 ) + end + it 'returns separate values for multiple given attributes' do + @test.name = 'david' + @test.age = 42 + @test.here = true + @test.cash = 9.57 + + expect( @test.name ).to eq( 'david' ) + expect( @test.age ).to eq( 42 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.57 ) + end +end diff --git a/spec/unit/virtus/lite/multiples_spec.rb-e b/spec/unit/virtus/lite/multiples_spec.rb-e new file mode 100644 index 00000000..53e9a357 --- /dev/null +++ b/spec/unit/virtus/lite/multiples_spec.rb-e @@ -0,0 +1,65 @@ +require 'spec_helper' + +class PlainMultiplesTest + include Subvirtus + attribute :name, String + attribute :age, Integer + attribute :here, Boolean + attribute :cash, Float +end + +describe PlainMultiplesTest do + before do + @test = PlainMultiplesTest.new + end + + it 'returns nil initial values for multiple attributes' do + expect( @test.name ).to eq( nil ) + expect( @test.age ).to eq( nil ) + expect( @test.here ).to eq( nil ) + expect( @test.cash ).to eq( nil ) + end + it 'returns separate values for multiple given attributes' do + @test.name = 'david' + @test.age = 42 + @test.here = true + @test.cash = 9.57 + + expect( @test.name ).to eq( 'david' ) + expect( @test.age ).to eq( 42 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.57 ) + end +end + +class MultiplesTestWithDefaults + include Subvirtus + attribute :name, String, default: 'subvirtus' + attribute :age, Integer, default: 43 + attribute :here, Boolean, default: true + attribute :cash, Float, default: 9.99 +end + +describe MultiplesTestWithDefaults do + before do + @test = MultiplesTestWithDefaults.new + end + + it 'returns separate initial values for multiple attributes' do + expect( @test.name ).to eq( 'subvirtus' ) + expect( @test.age ).to eq( 43 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.99 ) + end + it 'returns separate values for multiple given attributes' do + @test.name = 'david' + @test.age = 42 + @test.here = true + @test.cash = 9.57 + + expect( @test.name ).to eq( 'david' ) + expect( @test.age ).to eq( 42 ) + expect( @test.here ).to eq( true ) + expect( @test.cash ).to eq( 9.57 ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/string_spec.rb b/spec/unit/virtus/lite/string_spec.rb new file mode 100644 index 00000000..f88bc6b2 --- /dev/null +++ b/spec/unit/virtus/lite/string_spec.rb @@ -0,0 +1,143 @@ +require 'spec_helper' + +class PlainStringTest + include Virtus::Lite + attribute :name, String +end + +describe PlainStringTest do + before do + @test = PlainStringTest.new + end + + it 'returns a string value given' do + @test.name = 'david' + expect( @test.name ).to eq( 'david' ) + end + it 'returns a string when given a string' do + @test.name = 'david' + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string when given an integer' do + @test.name = 42 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given integer' do + @test.name = 42 + expect( @test.name ).to eq( '42' ) + end + it 'returns a string when given an float' do + @test.name = 42.7 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given float' do + @test.name = 42.7 + expect( @test.name ).to eq( '42.7' ) + end + it 'returns a string when given a boolean' do + @test.name = true + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a "false" when given a false' do + @test.name = false + expect( @test.name ).to eq( 'false' ) + end + it 'returns a "true" when given a true' do + @test.name = true + expect( @test.name ).to eq( 'true' ) + end + it 'does not return a string when given a nil' do + @test.name = nil + expect( @test.name.is_a? String ).to be_falsey + end + it 'returns nil when given a nil' do + @test.name = nil + expect( @test.name ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.name ).to eq( nil ) + end + it 'returns to_s when passed something random without a defined to_s' do + class SomeClass; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end + it 'returns to_s when passed something random with a defined to_s' do + class SomeClass; def to_s; 'random'; end; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end +end + +class StringTestWithDefault + include Virtus::Lite + attribute :name, String, default: 'subvirtus' +end + +describe StringTestWithDefault do + before do + @test = StringTestWithDefault.new + end + + it 'returns a string value given' do + @test.name = 'david' + expect( @test.name ).to eq( 'david' ) + end + it 'returns a string when given a string' do + @test.name = 'david' + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string when given an integer' do + @test.name = 42 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given integer' do + @test.name = 42 + expect( @test.name ).to eq( '42' ) + end + it 'returns a string when given an float' do + @test.name = 42.7 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given float' do + @test.name = 42.7 + expect( @test.name ).to eq( '42.7' ) + end + it 'returns a string when given a boolean' do + @test.name = true + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a "false" when given a false' do + @test.name = false + expect( @test.name ).to eq( 'false' ) + end + it 'returns a "true" when given a true' do + @test.name = true + expect( @test.name ).to eq( 'true' ) + end + it 'returns a string when given a nil' do + @test.name = nil + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns the default when given a nil' do + @test.name = nil + expect( @test.name ).to eq( 'subvirtus' ) + end + it 'returns the default when nothing is passed in' do + expect( @test.name ).to eq( 'subvirtus' ) + end + it 'returns to_s when passed something random without a defined to_s' do + class SomeClass; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end + it 'returns to_s when passed something random with a defined to_s' do + class SomeClass; def to_s; 'random'; end; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end +end diff --git a/spec/unit/virtus/lite/string_spec.rb-e b/spec/unit/virtus/lite/string_spec.rb-e new file mode 100644 index 00000000..1b69faea --- /dev/null +++ b/spec/unit/virtus/lite/string_spec.rb-e @@ -0,0 +1,143 @@ +require 'spec_helper' + +class PlainStringTest + include Subvirtus + attribute :name, String +end + +describe PlainStringTest do + before do + @test = PlainStringTest.new + end + + it 'returns a string value given' do + @test.name = 'david' + expect( @test.name ).to eq( 'david' ) + end + it 'returns a string when given a string' do + @test.name = 'david' + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string when given an integer' do + @test.name = 42 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given integer' do + @test.name = 42 + expect( @test.name ).to eq( '42' ) + end + it 'returns a string when given an float' do + @test.name = 42.7 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given float' do + @test.name = 42.7 + expect( @test.name ).to eq( '42.7' ) + end + it 'returns a string when given a boolean' do + @test.name = true + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a "false" when given a false' do + @test.name = false + expect( @test.name ).to eq( 'false' ) + end + it 'returns a "true" when given a true' do + @test.name = true + expect( @test.name ).to eq( 'true' ) + end + it 'does not return a string when given a nil' do + @test.name = nil + expect( @test.name.is_a? String ).to be_falsey + end + it 'returns nil when given a nil' do + @test.name = nil + expect( @test.name ).to eq( nil ) + end + it 'returns nil when nothing is passed in' do + expect( @test.name ).to eq( nil ) + end + it 'returns to_s when passed something random without a defined to_s' do + class SomeClass; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end + it 'returns to_s when passed something random with a defined to_s' do + class SomeClass; def to_s; 'random'; end; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end +end + +class StringTestWithDefault + include Subvirtus + attribute :name, String, default: 'subvirtus' +end + +describe StringTestWithDefault do + before do + @test = StringTestWithDefault.new + end + + it 'returns a string value given' do + @test.name = 'david' + expect( @test.name ).to eq( 'david' ) + end + it 'returns a string when given a string' do + @test.name = 'david' + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string when given an integer' do + @test.name = 42 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given integer' do + @test.name = 42 + expect( @test.name ).to eq( '42' ) + end + it 'returns a string when given an float' do + @test.name = 42.7 + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a string representive of a given float' do + @test.name = 42.7 + expect( @test.name ).to eq( '42.7' ) + end + it 'returns a string when given a boolean' do + @test.name = true + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns a "false" when given a false' do + @test.name = false + expect( @test.name ).to eq( 'false' ) + end + it 'returns a "true" when given a true' do + @test.name = true + expect( @test.name ).to eq( 'true' ) + end + it 'returns a string when given a nil' do + @test.name = nil + expect( @test.name.is_a? String ).to be_truthy + end + it 'returns the default when given a nil' do + @test.name = nil + expect( @test.name ).to eq( 'subvirtus' ) + end + it 'returns the default when nothing is passed in' do + expect( @test.name ).to eq( 'subvirtus' ) + end + it 'returns to_s when passed something random without a defined to_s' do + class SomeClass; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end + it 'returns to_s when passed something random with a defined to_s' do + class SomeClass; def to_s; 'random'; end; end + some_class = SomeClass.new + @test.name = some_class + expect( @test.name ).to eq( some_class.to_s ) + end +end \ No newline at end of file diff --git a/spec/unit/virtus/lite/value_object_spec.rb-e b/spec/unit/virtus/lite/value_object_spec.rb-e new file mode 100644 index 00000000..e33822b8 --- /dev/null +++ b/spec/unit/virtus/lite/value_object_spec.rb-e @@ -0,0 +1,34 @@ +require 'spec_helper' + +class ValueObjectTest + include Subvirtus.value_object + values do + attribute :name, String + attribute :age, Integer, default: 42 + end +end + +describe ValueObjectTest do + before do + @test = ValueObjectTest.new + end + + it 'has a working name attribute' do + @test.name = 'subvirtus' + expect( @test.name ).to eq( 'subvirtus' ) + end + it 'has a working age attribute with default value' do + expect( @test.age ).to eq( 42 ) + end + it 'considers objects with different values to not be equal' do + @test.name = 'subvirtus' + @test2 = ValueObjectTest.new( { name: 'david', age: 43 } ) + expect( @test == @test2 ).to be_falsey + end + it 'considers objects with same values to be equal' do + @test.name = 'david' + @test.age = 43 + @test2 = ValueObjectTest.new( { name: 'david', age: 43 } ) + expect( @test == @test2 ).to be_truthy + end +end \ No newline at end of file