icss 0.1.3 → 0.3.2

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.
Files changed (98) hide show
  1. data/.watchr +35 -3
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +19 -14
  4. data/README.md +296 -0
  5. data/Rakefile +2 -6
  6. data/TODO.md +13 -0
  7. data/VERSION +1 -1
  8. data/examples/avro_examples/complicated.icss.yaml +14 -13
  9. data/examples/bnc.icss.yaml +70 -0
  10. data/examples/chronic.icss.yaml +3 -3
  11. data/examples/license.icss.yaml +7 -0
  12. data/examples/source1.icss.yaml +4 -0
  13. data/examples/source2.icss.yaml +4 -0
  14. data/examples/test_icss.yaml +67 -0
  15. data/icss.gemspec +103 -43
  16. data/lib/icss.rb +37 -15
  17. data/lib/icss/core_types.rb +19 -0
  18. data/lib/icss/error.rb +4 -0
  19. data/{init.rb → lib/icss/init.rb} +0 -0
  20. data/lib/icss/message.rb +124 -66
  21. data/lib/icss/message/message_sample.rb +144 -0
  22. data/lib/icss/protocol.rb +184 -131
  23. data/lib/icss/protocol/code_asset.rb +18 -0
  24. data/lib/icss/protocol/data_asset.rb +23 -0
  25. data/lib/icss/protocol/license.rb +41 -0
  26. data/lib/icss/protocol/source.rb +37 -0
  27. data/lib/icss/protocol/target.rb +68 -0
  28. data/lib/icss/receiver_model.rb +24 -0
  29. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  30. data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
  31. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  32. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  33. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  34. data/lib/icss/receiver_model/locale/en.yml +27 -0
  35. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  36. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  37. data/lib/icss/receiver_model/validations.rb +31 -0
  38. data/lib/icss/serialization.rb +51 -0
  39. data/lib/icss/serialization/zaml.rb +443 -0
  40. data/lib/icss/type.rb +148 -501
  41. data/lib/icss/type/base_type.rb +0 -0
  42. data/lib/icss/type/named_type.rb +184 -0
  43. data/lib/icss/type/record_field.rb +77 -0
  44. data/lib/icss/type/record_model.rb +49 -0
  45. data/lib/icss/type/record_schema.rb +54 -0
  46. data/lib/icss/type/record_type.rb +325 -0
  47. data/lib/icss/type/simple_types.rb +72 -0
  48. data/lib/icss/type/structured_schema.rb +288 -0
  49. data/lib/icss/type/type_factory.rb +144 -0
  50. data/lib/icss/type/union_schema.rb +41 -0
  51. data/lib/icss/view_helper.rb +56 -19
  52. data/notes/named_array.md +32 -0
  53. data/notes/on_include_vs_extend_etc.rb +176 -0
  54. data/notes/technical_details.md +278 -0
  55. data/spec/core_types_spec.rb +119 -0
  56. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  57. data/spec/icss_spec.rb +86 -23
  58. data/spec/message/message_sample_spec.rb +4 -0
  59. data/spec/message_spec.rb +139 -0
  60. data/spec/protocol/license_spec.rb +67 -0
  61. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  62. data/spec/protocol/protocol_validations_spec.rb +176 -0
  63. data/spec/protocol/source_spec.rb +65 -0
  64. data/spec/protocol_spec.rb +91 -37
  65. data/spec/receiver_model_spec.rb +111 -0
  66. data/spec/serialization/zaml_spec.rb +81 -0
  67. data/spec/serialization/zaml_test.rb +473 -0
  68. data/spec/serialization_spec.rb +63 -0
  69. data/spec/spec_helper.rb +24 -7
  70. data/spec/support/icss_test_helper.rb +67 -0
  71. data/spec/support/load_example_protocols.rb +17 -0
  72. data/spec/type/base_type_spec.rb +0 -0
  73. data/spec/type/named_type_spec.rb +75 -0
  74. data/spec/type/record_field_spec.rb +44 -0
  75. data/spec/type/record_model_spec.rb +206 -0
  76. data/spec/type/record_schema_spec.rb +161 -0
  77. data/spec/type/record_type_spec.rb +155 -0
  78. data/spec/type/simple_types_spec.rb +121 -0
  79. data/spec/type/structured_schema_spec.rb +300 -0
  80. data/spec/type/type_catalog_spec.rb +44 -0
  81. data/spec/type/type_factory_spec.rb +93 -0
  82. data/spec/type/union_schema_spec.rb +0 -0
  83. data/spec/type_spec.rb +63 -0
  84. metadata +205 -144
  85. data/CHANGELOG.textile +0 -9
  86. data/Gemfile.lock +0 -40
  87. data/README.textile +0 -29
  88. data/lib/icss/brevity.rb +0 -136
  89. data/lib/icss/code_asset.rb +0 -16
  90. data/lib/icss/core_ext.rb +0 -9
  91. data/lib/icss/data_asset.rb +0 -22
  92. data/lib/icss/old.rb +0 -96
  93. data/lib/icss/protocol_set.rb +0 -48
  94. data/lib/icss/sample_message_call.rb +0 -142
  95. data/lib/icss/target.rb +0 -72
  96. data/lib/icss/type/factory.rb +0 -196
  97. data/lib/icss/validations.rb +0 -16
  98. data/spec/validations_spec.rb +0 -171
@@ -0,0 +1,63 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+ require 'time'
3
+ require 'icss'
4
+ require ENV.root_path('spec/support/icss_test_helper')
5
+ include IcssTestHelper
6
+
7
+ module Fake
8
+ class Thing
9
+ include Icss::ReceiverModel
10
+ field :name, String
11
+ field :description, String
12
+ end
13
+
14
+ class GeoCoordinates
15
+ include Icss::ReceiverModel
16
+ field :longitude, Float, :validates => { :numericality => { :>= => -180, :<= => 180 } }
17
+ field :latitude, Float, :validates => { :numericality => { :>= => -90, :<= => 90 } }
18
+ def coordinates
19
+ [ longitude, latitude ]
20
+ end
21
+ end
22
+
23
+ class Place < Thing
24
+ field :geo, GeoCoordinates
25
+ end
26
+
27
+ class MenuItem < Thing
28
+ field :price, Float, :required => true
29
+ end
30
+
31
+ class TacoTrailer < Place
32
+ field :menu, Array, :items => MenuItem
33
+ field :founding_date, Time
34
+ end
35
+ end
36
+
37
+ TORCHYS_HSH = {
38
+ :name => "Torchy's Taco's",
39
+ :geo => { :longitude => 30.295, :latitude => -97.745 },
40
+ :menu => [
41
+ { :name => "Dirty Sanchez", :price => 3.50 },
42
+ { :name => "Fried Avocado", :price => 2.95 }
43
+ ],
44
+ :founding_date => '2006-08-01T00:00:00Z',
45
+ }
46
+
47
+ describe Icss::ReceiverModel do
48
+ let(:torchys) do
49
+ Fake::TacoTrailer.receive(TORCHYS_HSH)
50
+ end
51
+
52
+ context 'serializations' do
53
+
54
+ context '#to_wire' do
55
+ it 'works on a complex record' do
56
+ # p torchys
57
+ # p torchys.to_wire
58
+ torchys.to_wire.should == TORCHYS_HSH
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -1,16 +1,33 @@
1
- require 'rubygems'
2
1
  require 'spork'
3
2
  require 'rspec'
4
3
 
5
- ICSS_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__),'..'))
6
- def ICSS_ROOT_DIR *paths
7
- File.join(::ICSS_ROOT_DIR, *paths)
4
+ def ENV.root_path(*args)
5
+ File.expand_path(File.join(File.dirname(__FILE__), '..', *args))
8
6
  end
9
7
 
10
8
  Spork.prefork do # Must restart for changes to config / code from libraries loaded here
11
- $LOAD_PATH.unshift(ICSS_ROOT_DIR('lib'))
12
- $LOAD_PATH.unshift(ICSS_ROOT_DIR('spec/support'))
13
- Dir[ICSS_ROOT_DIR('spec/support/matchers/*.rb')].each {|f| require f}
9
+ $LOAD_PATH.unshift(ENV.root_path('lib'))
10
+ Dir[ENV.root_path('spec/support/matchers/*.rb')].each {|f| require f}
11
+
12
+ require 'awesome_print'
13
+
14
+ require 'gorillib/object/blank'
15
+ require 'gorillib/object/try_dup'
16
+ require 'gorillib/string/inflections'
17
+ require 'gorillib/string/constantize'
18
+ require 'gorillib/array/compact_blank'
19
+ require 'gorillib/array/extract_options'
20
+ require 'gorillib/hash/compact'
21
+ require 'gorillib/hash/keys'
22
+ require 'gorillib/hash/tree_merge'
23
+ require 'gorillib/metaprogramming/class_attribute'
24
+ require 'gorillib/hashlike'
25
+
26
+ require 'yaml'
27
+ require 'json' unless defined?(JSON)
28
+
29
+ # note: please do NOT include library methods here.
30
+ # They should be painfully explicity included in your specs.
14
31
 
15
32
  # Configure rspec
16
33
  RSpec.configure do |config|
@@ -0,0 +1,67 @@
1
+ module IcssTestHelper
2
+ FALSE_PARENTS = %w[Boolean Icss::Mu::EpochTime Long Double]
3
+
4
+ SIMPLE_TYPES_TO_TEST = {
5
+ :null => [ ::NilClass, NilClass, nil],
6
+ :boolean => [ ::Boolean, TrueClass, true],
7
+ :int => [ ::Integer, Integer, 1],
8
+ :long => [ ::Long, Integer, 1],
9
+ :float => [ ::Float, Float, 1.0],
10
+ :double => [ ::Double, Float, 1.0],
11
+ :string => [ ::String, String, "hello"],
12
+ :bytes => [ ::Binary, String, "hello"],
13
+ :binary => [ ::Binary, String, "hello"],
14
+ :integer => [ ::Integer, Integer, 1],
15
+ :regexp => [ ::Regexp, Regexp, /a/],
16
+ :numeric => [ ::Numeric, ::Numeric, 1.0],
17
+ :symbol => [ ::Symbol, Symbol, :bob],
18
+ :time => [ ::Time, Time, Time.now],
19
+ }
20
+
21
+
22
+ def remove_icss_constants(*names)
23
+ ['Icss', 'Icss::Meta'].each do |outer_mod|
24
+ names.each do |name|
25
+ name_parts = name.to_s.split(/::/)
26
+ const_name = name_parts.pop
27
+ parent_mod = ([outer_mod]+name_parts).join('::')
28
+ ['', 'Type', 'Model'].each do |tail|
29
+ remove_potential_constant(parent_mod, const_name+tail)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def remove_potential_constant(parent_mod, const_name)
36
+ begin
37
+ parent_mod = (parent_mod.is_a?(Module) ? parent_mod : parent_mod.to_s.constantize)
38
+ rescue ; return ; end
39
+ parent_mod.send(:remove_const, const_name) if parent_mod.const_defined?(const_name)
40
+ end
41
+ end
42
+
43
+ module Icss
44
+ module This
45
+ module That
46
+ class TheOther
47
+ end
48
+ end
49
+ module Blinken ; end
50
+ end
51
+ end
52
+
53
+ if defined?(Icss::Meta::RecordModel)
54
+ module Icss
55
+ class SmurfRecord
56
+ include Icss::Meta::RecordModel
57
+ end
58
+ end
59
+ end
60
+
61
+ if defined?(Icss::ReceiverModel)
62
+ module Icss
63
+ class SmurfModel
64
+ include Icss::ReceiverModel
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module Icss
2
+ module Spec
3
+ module LoadExampleProtocols
4
+
5
+ def load_example_protocols
6
+ [
7
+ Dir[ENV.root_path('examples/hackboxen/**/*.icss.yaml')],
8
+ Dir[ENV.root_path('examples/apeyeye_endpoints/**/*.icss.yaml')],
9
+ ].flatten[0.. -1].each do |icss_filename|
10
+ next if icss_filename =~ %r{culture/art}
11
+ Icss::Meta::Protocol.receive_from_file(icss_filename)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
File without changes
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss/type'
3
+ require 'icss/type/simple_types'
4
+ require 'icss/type/named_type'
5
+
6
+ describe Icss::Meta::NamedType do
7
+
8
+ module Icss
9
+ module This
10
+ module That
11
+ class TheOther
12
+ end
13
+ end
14
+ end
15
+ Blinken = 7
16
+ end
17
+ #
18
+ # modules defined outside of Icss with the same names will cause problems
19
+ # unless const_defined? and const_get are used correctly
20
+ #
21
+ module Nod
22
+ end
23
+ module Wears
24
+ end
25
+
26
+ context '.make' do
27
+ it 'succeeds when the class already exists' do
28
+ klass, klass_metamodel = Icss::Meta::NamedType.make('this.that.the_other', Object)
29
+ klass.should be_a(Class)
30
+ klass.name.should == 'Icss::This::That::TheOther'
31
+ klass_metamodel.should be_a(Module)
32
+ klass_metamodel.name.should == 'Icss::Meta::This::That::TheOtherModel'
33
+ end
34
+ it 'succeeds when the class does not already exist' do
35
+ Icss.should_not be_const_defined(:YourMom)
36
+ klass, klass_metamodel = Icss::Meta::NamedType.make('your_mom.wears.combat_boots', Hash)
37
+ klass.name.should == 'Icss::YourMom::Wears::CombatBoots'
38
+ klass.should < Hash
39
+ Icss::Meta::YourMom::Wears::CombatBootsModel.class.should == Module
40
+ Icss::Meta::YourMom::Wears.class.should == Module
41
+ Icss::YourMom::Wears::CombatBoots.class.should == Class
42
+ Icss::YourMom::Wears.class.should == Module
43
+ Icss::Meta.send(:remove_const, :YourMom)
44
+ Icss.send(:remove_const, :YourMom)
45
+ end
46
+ it 'creates a klass which inherits (includes) its metatype' do
47
+ klass, klass_metamodel = Icss::Meta::NamedType.make('this.that.the_other', Object)
48
+ klass.metamodel.should == Icss::Meta::This::That::TheOtherModel
49
+ end
50
+ end
51
+
52
+ context '.get_nested_module' do
53
+ it 'adds a new child when parents exist' do
54
+ Icss::This::That.should_not be_const_defined(:AlsoThis)
55
+ new_module = Icss::Meta::NamedType.get_nested_module(%w[Icss This That AlsoThis])
56
+ new_module.name.should == 'Icss::This::That::AlsoThis'
57
+ Icss::This::That::AlsoThis.class.should == Module
58
+ Icss::This::That.send(:remove_const, :AlsoThis)
59
+ end
60
+ it 'adds parents as necessary' do
61
+ Icss.should_not be_const_defined(:Winken)
62
+ new_module = Icss::Meta::NamedType.get_nested_module(%w[Icss Winken Blinken Nod])
63
+ new_module.name.should == 'Icss::Winken::Blinken::Nod'
64
+ Icss::Winken::Blinken::Nod.class.should == Module
65
+ Icss::Winken::Blinken.class.should == Module
66
+ Icss::Winken.class.should == Module
67
+ Icss.send(:remove_const, :Winken)
68
+ end
69
+ end
70
+
71
+ context '.define_metamodel_method' do
72
+ it 'does not overwrite an existing method'
73
+ end
74
+
75
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss'
3
+ require ENV.root_path('spec/support/icss_test_helper')
4
+ include IcssTestHelper
5
+
6
+ describe Icss::Meta::RecordType do
7
+ before do
8
+ IcssTestHelper.remove_icss_constants('Handy')
9
+ class Icss::Handy < Icss::SmurfRecord ; end
10
+ end
11
+
12
+ context '.field' do
13
+ it 'with record_field loaded, adds RecordFields not hashes' do
14
+ Icss::Handy.field :foo, Integer
15
+ Icss::Handy.field_named(:foo).should be_a(Icss::Meta::RecordField)
16
+ end
17
+
18
+ it 'allows sloppy complex types when I use Hash' do
19
+ Icss::Handy.field :foo, Hash, :values => Integer
20
+ fld = Icss::Handy.field_named(:foo)
21
+ fld.type.to_s.should == 'Icss::HashOfInteger'
22
+ fld.type.values == Integer
23
+ end
24
+
25
+ it 'allows sloppy complex types when I use Array' do
26
+ Icss::Handy.field :foo, Array, :items => Integer
27
+ fld = Icss::Handy.field_named(:foo)
28
+ fld.type.to_s.should == 'Icss::ArrayOfInteger'
29
+ fld.type.items == Integer
30
+ end
31
+
32
+ it 'does not allow sloppy complex types when I use :hash' do
33
+ lambda{ Icss::Handy.field :bar, :hash, :values => Integer }.should raise_error
34
+ end
35
+
36
+ it 'handles complex fields in line' do
37
+ Icss::Handy.field :foo, { :type => :hash, :values => Integer }
38
+ fld = Icss::Handy.field_named(:foo)
39
+ fld.type.to_s.should == 'Icss::HashOfInteger'
40
+ fld.type.values == Integer
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,206 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'gorillib/object/try_dup'
3
+ require 'icss/receiver_model/acts_as_hash'
4
+ require 'icss/receiver_model/active_model_shim'
5
+ require 'icss/type' #
6
+ require 'icss/type/simple_types' # Boolean, Integer, ...
7
+ require 'icss/type/named_type' # class methods for a named type: .metamodel .doc, .fullname, &c
8
+ require 'icss/type/record_type' # class methods for a record model: .field, .receive,
9
+ require 'icss/type/record_model' # instance methods for a record model
10
+ #
11
+ require 'icss/type/type_factory' #
12
+ require 'icss/type/structured_schema'
13
+ require 'icss/type/record_schema'
14
+ require 'icss/type/record_field'
15
+
16
+ require ENV.root_path('spec/support/icss_test_helper')
17
+ include IcssTestHelper
18
+
19
+ describe Icss::Meta::RecordModel do
20
+
21
+ before(:each) do
22
+ IcssTestHelper.remove_icss_constants('Poppa', 'Brainy', 'Smurfette', 'Hefty', 'Glad')
23
+ module Icss
24
+ class Poppa < Icss::SmurfRecord
25
+ field :smurfiness, Integer
26
+ end
27
+ module Brainy
28
+ include Icss::Meta::RecordModel
29
+ field :has_glasses, Boolean
30
+ end
31
+ class Smurfette < Poppa
32
+ include Brainy
33
+ field :blondness, Integer
34
+ end
35
+ class Hefty < Icss::SmurfRecord
36
+ end
37
+ class Glad < Hefty
38
+ end
39
+ end
40
+ end
41
+
42
+ let(:poppa ){ Icss::Poppa.new() }
43
+ let(:smurfette ){ Icss::Smurfette.new() }
44
+
45
+ context '#receive!' do
46
+ it 'sets values' do
47
+ smurfette.receive!({ :smurfiness => '98', :blondness => 12.7 })
48
+ smurfette.smurfiness.should == 98
49
+ smurfette.blondness.should == 12
50
+ end
51
+ it 'handles values with #receive_foo methods' do
52
+ smurfette.should_receive(:receive_smurfiness).with('99')
53
+ smurfette.receive!({ :smurfiness => '99' })
54
+ end
55
+ it 'which goes through _set_field_val' do
56
+ smurfette.should_receive(:_set_field_val).with(:smurfiness, 100)
57
+ smurfette.receive!({ :smurfiness => '100' })
58
+ end
59
+ it 'sends to field type klass .receive method' do
60
+ dummy = mock
61
+ foo_type = Class.new
62
+ Icss::Poppa.field :foo, foo_type
63
+ #
64
+ foo_type.should_receive(:receive).with(dummy)
65
+ Icss::Poppa.receive({ :foo => dummy })
66
+ end
67
+ end
68
+
69
+ context 'decorates instances' do
70
+ it 'with accessors and receivers' do
71
+ [:smurfiness, :has_glasses, :blondness].each do |f|
72
+ smurfette.should respond_to(f)
73
+ smurfette.should respond_to("#{f}=")
74
+ end
75
+ smurfette.should respond_to(:receive_smurfiness)
76
+ smurfette.should respond_to(:receive_blondness)
77
+ smurfette.blondness.should == nil
78
+ smurfette.blondness = 77
79
+ smurfette.blondness.should == 77
80
+ smurfette.receive_blondness(99)
81
+ smurfette.blondness.should == 99
82
+ end
83
+ end
84
+
85
+ context '.after_receive' do
86
+ it 'adds an after_receiver' do
87
+ blk = lambda{ 1 }
88
+ Icss::Poppa.after_receive(:foo, &blk)
89
+ Icss::Poppa.after_receivers[:foo].should == blk
90
+ end
91
+ end
92
+
93
+ context '.after_receivers' do
94
+ it 'is run after receive' do
95
+ dummy = mock ; hsh = { :smurfiness => 9 }
96
+ Icss::Poppa.after_receive(:howdy){|hsh| dummy.hello("hello!", smurfiness) }
97
+ dummy.should_receive(:hello).with("hello!", 9)
98
+ Icss::Poppa.receive(hsh)
99
+ end
100
+ it 'gets received hash as args' do
101
+ dummy = mock ; hsh = { :smurfiness => 10 }
102
+ Icss::Poppa.after_receive(:howdy){|hsh| dummy.hello("hello!", hsh) }
103
+ dummy.should_receive(:hello).with("hello!", hsh)
104
+ Icss::Poppa.receive(hsh)
105
+ end
106
+ end
107
+
108
+ context '.rcvr_remaining' do
109
+ it 'adds a new field' do
110
+ Icss::Poppa.rcvr_remaining(:bob)
111
+ Icss::Poppa.field_names.should == [:smurfiness, :bob]
112
+ Icss::Poppa.field_named(:bob)[:type].to_s.should == 'Icss::HashOfMetaDotIdenticalFactory'
113
+ end
114
+ it 'receives leftover attrs' do
115
+ Icss::Poppa.rcvr_remaining(:bob)
116
+ obj = Icss::Poppa.receive(:smurfiness => 12, :bogosity => 97)
117
+ obj.bob.should == {:bogosity => 97}
118
+ end
119
+ it 'applies schema to leftover attrs' do
120
+ Icss::Poppa.rcvr_remaining(:bob, :values => :int)
121
+ obj = Icss::Poppa.receive({:smurfiness => 12, :bogosity => "11", :converts => 31.2})
122
+ obj.bob.should == {:bogosity => 11, :converts => 31}
123
+ end
124
+ it 'is {} when no leftover attrs' do
125
+ Icss::Poppa.rcvr_remaining(:bob)
126
+ obj = Icss::Poppa.receive({:smurfiness => 12})
127
+ obj.bob.should == {}
128
+ obj = Icss::Poppa.receive({})
129
+ obj.bob.should == {}
130
+ end
131
+ end
132
+
133
+ context ':default =>' do
134
+ before do
135
+ Icss::Hefty.field :tool, Symbol, :default => :smurfwrench
136
+ Icss::Hefty.field :weapon, Symbol, :default => :smurfthrower
137
+ Icss::Hefty.field :no_default, Symbol
138
+ end
139
+ let(:hefty_smurf){ Icss::Hefty.receive({ :tool => :smurfwrench }) }
140
+ let(:glad_smurf ){ Icss::Glad.receive({ :tool => :smurfwrench }) }
141
+
142
+ it 'sets default' do
143
+ hefty_smurf.tool.should == :smurfwrench
144
+ hefty_smurf.weapon.should == :smurfthrower
145
+ hefty_smurf.no_default.should be_nil
146
+ hefty_smurf.attr_set?(:no_default).should be_false
147
+ end
148
+
149
+ it 'does not set default if explicitly nil' do
150
+ hefty_smurf = Icss::Hefty.receive({ :tool => :smurfwrench, :weapon => nil })
151
+ hefty_smurf.weapon.should == nil
152
+ hefty_smurf.attr_set?(:weapon).should be_true
153
+ end
154
+
155
+ it 'uses an after_receiver with a predictable name' do
156
+ Icss::Hefty.after_receivers[:default_tool].should be_a(Proc)
157
+ end
158
+
159
+ it 'is overridable' do
160
+ proc_before = Icss::Hefty.after_receivers[:default_weapon]
161
+ Icss::Hefty.field :weapon, Symbol, :default => :flamesmurf
162
+ Icss::Hefty.after_receivers[:default_weapon].should_not == proc_before
163
+ hefty_smurf.weapon.should == :flamesmurf
164
+ end
165
+
166
+ it 'is overridable in subclass without affecting parent' do
167
+ hefty_proc = Icss::Hefty.after_receivers[:default_weapon]
168
+ Icss::Glad.field :weapon, Symbol, :default => :flamesmurf
169
+ Icss::Hefty.after_receivers[:default_weapon].should == hefty_proc
170
+ Icss::Glad.after_receivers[ :default_weapon].should_not == hefty_proc
171
+ hefty_smurf.weapon.should == :smurfthrower
172
+ glad_smurf.weapon.should == :flamesmurf
173
+ end
174
+
175
+ it 'try_dups the object when setting default' do
176
+ smurfed_cheese = mock
177
+ Icss::Hefty.field :food, Symbol, :default => smurfed_cheese
178
+ smurfed_cheese.should_receive(:try_dup).with()
179
+ hefty_smurf
180
+ end
181
+
182
+ it 'accepts a proc' do
183
+ dummy = mock
184
+ Icss::Glad.field :weapon, Symbol, :default => lambda{ [dummy, tool, self] }
185
+ glad_smurf.weapon.should == [dummy, :smurfwrench, glad_smurf]
186
+ end
187
+
188
+ context 'can also be set with set_field_default' do
189
+ it 'with a value' do
190
+ dummy = mock
191
+ Icss::Glad.class_eval do
192
+ set_field_default :weapon, :gatlingsmurf
193
+ end
194
+ glad_smurf.weapon.should == :gatlingsmurf
195
+ end
196
+ it 'with a proc' do
197
+ dummy = mock
198
+ Icss::Glad.class_eval do
199
+ set_field_default :weapon, lambda{ [dummy, tool, self] }
200
+ end
201
+ glad_smurf.weapon.should == [dummy, :smurfwrench, glad_smurf]
202
+ end
203
+ end
204
+ end
205
+
206
+ end