freeform 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/.gitignore +8 -17
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +150 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +31 -43
  6. data/Rakefile +32 -1
  7. data/freeform.gemspec +22 -15
  8. data/lib/freeform/builder/builder_mixin.rb +111 -0
  9. data/lib/freeform/builder/builders.rb +32 -0
  10. data/lib/freeform/builder/engine.rb +14 -0
  11. data/lib/freeform/builder/view_helper.rb +56 -0
  12. data/lib/freeform/form/form_input_key.rb +1 -1
  13. data/lib/freeform/form/nested.rb +17 -55
  14. data/lib/freeform/form/property.rb +82 -42
  15. data/lib/freeform/form/validation.rb +38 -11
  16. data/lib/freeform/form.rb +24 -27
  17. data/lib/freeform/version.rb +1 -1
  18. data/lib/freeform.rb +4 -0
  19. data/lib/generators/freeform/install_generator.rb +17 -0
  20. data/lib/tasks/freeform_tasks.rake +4 -0
  21. data/spec/acceptance_spec.rb +261 -155
  22. data/spec/builder/builder_spec.rb +215 -0
  23. data/spec/builder/view_helper_spec.rb +97 -0
  24. data/spec/dummy/README.rdoc +28 -0
  25. data/spec/dummy/Rakefile +6 -0
  26. data/spec/dummy/app/assets/images/.keep +0 -0
  27. data/spec/dummy/app/assets/javascripts/application.js +5 -0
  28. data/spec/dummy/app/assets/javascripts/jquery.js +9404 -0
  29. data/spec/dummy/app/assets/javascripts/jquery_events_test.js +19 -0
  30. data/spec/dummy/app/assets/javascripts/projects.js +2 -0
  31. data/spec/dummy/app/assets/javascripts/prototype.js +6082 -0
  32. data/spec/dummy/app/assets/javascripts/prototype_events_test.js +20 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  34. data/spec/dummy/app/assets/stylesheets/companies.css +4 -0
  35. data/spec/dummy/app/assets/stylesheets/projects.css +4 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  37. data/spec/dummy/app/controllers/companies_controller.rb +5 -0
  38. data/spec/dummy/app/controllers/projects_controller.rb +11 -0
  39. data/spec/dummy/app/forms/milestone_form.rb +4 -0
  40. data/spec/dummy/app/forms/project_form.rb +11 -0
  41. data/spec/dummy/app/forms/task_form.rb +10 -0
  42. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  43. data/spec/dummy/app/mailers/.keep +0 -0
  44. data/spec/dummy/app/models/.keep +0 -0
  45. data/spec/dummy/app/models/company.rb +5 -0
  46. data/spec/dummy/app/models/milestone.rb +6 -0
  47. data/spec/dummy/app/models/project.rb +9 -0
  48. data/spec/dummy/app/models/project_task.rb +3 -0
  49. data/spec/dummy/app/models/task.rb +7 -0
  50. data/spec/dummy/app/views/companies/new.html.erb +16 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +19 -0
  52. data/spec/dummy/app/views/projects/new.html.erb +13 -0
  53. data/spec/dummy/app/views/projects/without_intermediate_inputs.html.erb +11 -0
  54. data/spec/dummy/bin/bundle +3 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/config/application.rb +35 -0
  58. data/spec/dummy/config/boot.rb +5 -0
  59. data/spec/dummy/config/database.yml +25 -0
  60. data/spec/dummy/config/environment.rb +5 -0
  61. data/spec/dummy/config/environments/development.rb +29 -0
  62. data/spec/dummy/config/environments/production.rb +80 -0
  63. data/spec/dummy/config/environments/test.rb +36 -0
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  66. data/spec/dummy/config/initializers/inflections.rb +16 -0
  67. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  68. data/spec/dummy/config/initializers/secret_token.rb +13 -0
  69. data/spec/dummy/config/initializers/session_store.rb +3 -0
  70. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  71. data/spec/dummy/config/locales/en.yml +23 -0
  72. data/spec/dummy/config/routes.rb +5 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +38 -0
  75. data/spec/dummy/db/schema.rb +43 -0
  76. data/spec/dummy/db/test.sqlite3 +0 -0
  77. data/spec/dummy/lib/assets/.keep +0 -0
  78. data/spec/dummy/log/.keep +0 -0
  79. data/spec/dummy/log/development.log +0 -0
  80. data/spec/dummy/log/test.log +39736 -0
  81. data/spec/dummy/public/404.html +58 -0
  82. data/spec/dummy/public/422.html +58 -0
  83. data/spec/dummy/public/500.html +57 -0
  84. data/spec/dummy/public/favicon.ico +0 -0
  85. data/spec/dummy/tmp/cache/assets/C54/850/sprockets%2Fd484f47085686f151320ff7248bb5105 +0 -0
  86. data/spec/dummy/tmp/cache/assets/C76/160/sprockets%2F49c594d143212b346d11f1ecf9358103 +0 -0
  87. data/spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123 +0 -0
  88. data/spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d +0 -0
  89. data/spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3 +0 -0
  90. data/spec/dummy/tmp/cache/assets/CB2/CB0/sprockets%2F11cc8d161d71a716dd36f16849d90870 +0 -0
  91. data/spec/dummy/tmp/cache/assets/CB7/7F0/sprockets%2Fac97b043470f6fcc925c352f16956643 +0 -0
  92. data/spec/dummy/tmp/cache/assets/CBA/680/sprockets%2F912d84e091e5f2190b1ab7926de19679 +0 -0
  93. data/spec/dummy/tmp/cache/assets/CC7/430/sprockets%2F48e99a3e16ba3e65749e009d82546f94 +0 -0
  94. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  95. data/spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d +0 -0
  96. data/spec/dummy/tmp/cache/assets/CF1/E80/sprockets%2F7735295e1e3085f2e1dc29d59a45e8e6 +0 -0
  97. data/spec/dummy/tmp/cache/assets/D0F/E60/sprockets%2F1123d9a479fdf5c2b8415087e2a43ec6 +0 -0
  98. data/spec/dummy/tmp/cache/assets/D1F/A10/sprockets%2F60317e62cb324bfd9987e8da9636fd06 +0 -0
  99. data/spec/dummy/tmp/cache/assets/D25/E20/sprockets%2F29ba1a4a2b611731334f54abb9e5b5d1 +0 -0
  100. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  101. data/spec/dummy/tmp/cache/assets/D35/760/sprockets%2F49e26620c5c743ac4cdab7703f54db06 +0 -0
  102. data/spec/dummy/tmp/cache/assets/D49/870/sprockets%2F90896142645585acc8baf56ad57e3afb +0 -0
  103. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  104. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  105. data/spec/dummy/tmp/cache/assets/D62/F00/sprockets%2F6ac03a007f26b1c18ed3d53498ad3eb8 +0 -0
  106. data/spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e +0 -0
  107. data/spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9 +0 -0
  108. data/spec/dummy/tmp/cache/assets/DA8/900/sprockets%2Fde7a2b3987b89b9d9afb268ce4204a4a +0 -0
  109. data/spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659 +0 -0
  110. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  111. data/spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534 +0 -0
  112. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  113. data/spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e +0 -0
  114. data/spec/dummy/tmp/cache/assets/E20/9B0/sprockets%2F2fa6cd86b1af7bda41f5b7921cdadf10 +0 -0
  115. data/spec/dummy/tmp/cache/assets/E3A/A60/sprockets%2F7c72c96cfc66454caf5fc8ca0fedd4f3 +0 -0
  116. data/spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81 +0 -0
  117. data/spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb +0 -0
  118. data/spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc +0 -0
  119. data/spec/form/nested_spec.rb +75 -61
  120. data/spec/form/property_spec.rb +167 -14
  121. data/spec/form/validation_spec.rb +46 -23
  122. data/spec/javascript_spec.rb +60 -0
  123. data/spec/persistence_spec.rb +608 -0
  124. data/spec/spec_helper.rb +18 -2
  125. data/vendor/assets/javascripts/jquery_freeform.js +120 -0
  126. data/vendor/assets/javascripts/jquery_nested_form.js +0 -0
  127. data/vendor/assets/javascripts/prototype_freeform.js +69 -0
  128. data/vendor/assets/javascripts/prototype_nested_form.js +0 -0
  129. metadata +341 -3
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -3,56 +3,72 @@ require 'freeform/form/property'
3
3
  require 'freeform/form/nested'
4
4
 
5
5
  describe FreeForm::Nested do
6
- describe "class methods", :class_methods => true do
7
- describe "has_many", :has_many => true do
8
- let(:form_class) do
9
- klass = Class.new(Module) do
10
- include FreeForm::Property
11
- include FreeForm::Nested
12
-
13
- has_many :mailing_addresses, :class_initializer => :mailing_address_initializer do
14
- declared_model :address
15
-
16
- property :street, :on => :address
17
- end
6
+ describe "has_many", :has_many => true do
7
+ let!(:nested_class) do
8
+ klass = Class.new(Module) do
9
+ include FreeForm::Property
10
+ include FreeForm::Nested
11
+ declared_model :address
12
+
13
+ property :street, :on => :address
14
+
15
+ def initialize(h={})
16
+ h.each {|k,v| send("#{k}=",v)}
17
+ end
18
+ end
19
+ # This wrapper just avoids CONST warnings
20
+ v, $VERBOSE = $VERBOSE, nil
21
+ Module.const_set("MailingAddressForm", klass)
22
+ $VERBOSE = v
23
+ klass
24
+ end
18
25
 
19
- def initialize(h={})
20
- h.each {|k,v| send("#{k}=",v)}
21
- end
26
+ let(:form_class) do
27
+ klass = Class.new(Module) do
28
+ include FreeForm::Property
29
+ include FreeForm::Nested
30
+
31
+ has_many :mailing_addresses, :class => Module::MailingAddressForm, :default_initializer => :mailing_address_initializer
32
+
33
+ def initialize(h={})
34
+ h.each {|k,v| send("#{k}=",v)}
35
+ end
36
+
37
+ def mailing_address_initializer
38
+ { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
22
39
  end
23
- # This wrapper just avoids CONST warnings
24
- v, $VERBOSE = $VERBOSE, nil
25
- Module.const_set("DummyForm", klass)
26
- $VERBOSE = v
27
- klass
28
- end
29
-
30
- let(:form) do
31
- form_class.mailing_address_initializer = lambda { { :address => OpenStruct.new } }
32
- form_model = form_class.new
33
40
  end
41
+ # This wrapper just avoids CONST warnings
42
+ v, $VERBOSE = $VERBOSE, nil
43
+ Module.const_set("DummyForm", klass)
44
+ $VERBOSE = v
45
+ klass
46
+ end
34
47
 
35
- describe "form class" do
36
- it "sets nested_form in models" do
37
- form_class.models.should eq([:mailing_addresses])
38
- end
48
+ let(:form) do
49
+ form_model = form_class.new
50
+ end
51
+
52
+ describe "form class" do
53
+ it "sets nested_form in models" do
54
+ form_class.models.should eq([:mailing_addresses])
55
+ end
56
+ end
57
+
58
+ describe "building nested models" do
59
+ it "initializes with no nested models prebuilt" do
60
+ form.mailing_addresses.should eq([])
39
61
  end
40
62
 
41
- describe "building nested models" do
42
- it "initializes with no nested models prebuilt" do
43
- form.mailing_addresses.should eq([])
44
- end
45
-
63
+ context "with default initializer" do
46
64
  it "allows nested_forms to be built" do
47
65
  form.build_mailing_addresses
48
66
  form.mailing_addresses.should be_an(Array)
49
67
  form.mailing_addresses.should_not be_empty
50
- form.mailing_addresses.first.should be_a(Module::DummyForm::MailingAddressesForm)
68
+ form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
51
69
  end
52
-
70
+
53
71
  it "builds unique models" do
54
- # Using module here, since they initialize uniquely
55
- form_class.mailing_address_initializer = lambda { { :address => Module.new } }
56
72
  form = form_class.new
57
73
  form.build_mailing_address
58
74
  form.build_mailing_address
@@ -60,36 +76,34 @@ describe FreeForm::Nested do
60
76
  address_2 = form.mailing_addresses.last.address
61
77
  address_1.should_not eq(address_2)
62
78
  end
63
-
64
- it "builds initialized models through reflection on association" do
65
- form_class.mailing_address_initializer = lambda { { :address => Module.new } }
66
- klass = form_class.reflect_on_association(:mailing_addresses).klass
67
- klass.new.address.should be_a(Module)
79
+ end
80
+
81
+ context "with custom initializer" do
82
+ it "allows nested_forms to be built" do
83
+ form.build_mailing_addresses(:address => OpenStruct.new)
84
+ form.mailing_addresses.should be_an(Array)
85
+ form.mailing_addresses.should_not be_empty
86
+ form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
68
87
  end
69
-
88
+
70
89
  it "allows nested_forms to be built with custom initializers" do
71
90
  form.build_mailing_address(:address => OpenStruct.new(:street => "1600 Pennsylvania Ave."))
72
91
  form.mailing_addresses.first.street.should eq("1600 Pennsylvania Ave.")
73
92
  end
93
+ end
94
+ end
95
+
96
+ describe "setting attributes" do
97
+ describe "nested attribute assignment" do
98
+ let(:attributes) do
99
+ { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
100
+ end
74
101
 
75
- it "reflects on association" do
76
- reflection = form_class.reflect_on_association(:mailing_addresses)
77
- reflection.klass.should eq(Module::DummyForm::MailingAddressesForm)
102
+ it "assigns nested attributes" do
103
+ form.fill(attributes)
104
+ form.mailing_addresses.first.street.should eq("123 Main St.")
78
105
  end
79
106
  end
80
-
81
- describe "setting attributes" do
82
- describe "nested attribute assignment" do
83
- let(:attributes) do
84
- { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
85
- end
86
-
87
- it "assigns nested attributes" do
88
- form.fill(attributes)
89
- form.mailing_addresses.first.street.should eq("123 Main St.")
90
- end
91
- end
92
- end
93
- end
107
+ end
94
108
  end
95
109
  end
@@ -141,6 +141,39 @@ describe FreeForm::Property do
141
141
  form_class.models.should eq([:test_model_1, :test_model_2])
142
142
  end
143
143
  end
144
+
145
+ describe "child models", :child_models => true do
146
+ let(:form_class) do
147
+ Class.new(Module) do
148
+ include FreeForm::Property
149
+ form_model :test_model_1
150
+ child_model :test_model_2 do
151
+ test_model_1.build_child
152
+ end
153
+
154
+ def initialize(h={})
155
+ h.each {|k,v| send("#{k}=",v)}
156
+ initialize_test_model_2
157
+ end
158
+ end
159
+ end
160
+
161
+ let(:form) do
162
+ form_class.new(
163
+ :test_model_1 => OpenStruct.new(:dummy => "yes",
164
+ :build_child => OpenStruct.new(:field => "child model"))
165
+ )
166
+ end
167
+
168
+ it "sets declared models as accessor" do
169
+ form.test_model_1.should eq(OpenStruct.new(:dummy => "yes", :build_child => OpenStruct.new(:field => "child model")))
170
+ form.test_model_2.should eq(OpenStruct.new(:field => "child model"))
171
+ end
172
+
173
+ it "sets @models in class to declared models" do
174
+ form_class.models.should eq([:test_model_1, :test_model_2])
175
+ end
176
+ end
144
177
  end
145
178
 
146
179
  describe "properties", :properties => true do
@@ -152,6 +185,7 @@ describe FreeForm::Property do
152
185
 
153
186
  property :attribute_1, :on => :test_model
154
187
  property :attribute_2, :on => :test_model, :ignore_blank => true
188
+ property :attribute_3, :as => :test_attribute_3, :on => :test_model
155
189
 
156
190
  def initialize(h={})
157
191
  h.each {|k,v| send("#{k}=",v)}
@@ -165,25 +199,144 @@ describe FreeForm::Property do
165
199
  )
166
200
  end
167
201
 
168
- it "delegates properties to models" do
169
- form.attribute_1.should eq("yes")
170
- form.attribute_2.should be_nil
171
- end
172
-
173
- it "allows properties to be written, and delegates the values" do
174
- form.attribute_1 = "changed"
175
- form.attribute_1.should eq("changed")
176
- form.test_model.attribute_1.should eq("changed")
177
- end
178
-
179
- it "tracks ignored blank fields" do
180
- form_class.ignored_blank_params.should eq([:attribute_2])
181
- end
202
+ describe "delegation" do
203
+ it "delegates properties to models" do
204
+ form.attribute_1.should eq("yes")
205
+ form.attribute_2.should be_nil
206
+ end
207
+
208
+ it "allows properties to be written, and delegates the values" do
209
+ form.attribute_1 = "changed"
210
+ form.attribute_1.should eq("changed")
211
+ form.test_model.attribute_1.should eq("changed")
212
+ end
213
+
214
+ it "delegates using :as" do
215
+ form.test_attribute_3.should be_nil
216
+ form.test_attribute_3 = "set_using_as"
217
+ form.test_attribute_3.should eq("set_using_as")
218
+ form.test_model.attribute_3.should eq("set_using_as")
219
+ end
220
+ end
221
+
222
+ describe "property_mappings" do
223
+ it "sets appropriate property mappings" do
224
+ form_class.property_mappings.should eq(
225
+ { :attribute_1 => {:model => :test_model, :field => :attribute_1, :ignore_blank => false},
226
+ :attribute_2 => {:model => :test_model, :field => :attribute_2, :ignore_blank => true},
227
+ :test_attribute_3 => {:model => :test_model, :field => :attribute_3, :ignore_blank => false}
228
+ }
229
+ )
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "allow_destroy_on_save", :allow_destroy_on_save => true do
235
+ let(:form_class) do
236
+ Class.new(Module) do
237
+ include FreeForm::Property
238
+ declared_model :test_model
239
+ allow_destroy_on_save
240
+
241
+ property :attribute_1, :on => :test_model
242
+ property :attribute_2, :on => :test_model, :ignore_blank => true
243
+
244
+ def initialize(h={})
245
+ h.each {|k,v| send("#{k}=",v)}
246
+ end
247
+ end
248
+ end
249
+
250
+ let(:form) do
251
+ form_class.new(:test_model => OpenStruct.new)
252
+ end
253
+
254
+ it "has _destroy accessor" do
255
+ form.should respond_to(:_destroy)
256
+ end
257
+
258
+ it "has marked_for_destruction? accessor" do
259
+ form.should respond_to(:marked_for_destruction?)
260
+ end
261
+
262
+ it "has destroy as false by default" do
263
+ form._destroy.should be_false
264
+ end
265
+
266
+ it "has marked_for_destruction? as false by default" do
267
+ form.marked_for_destruction?.should be_false
268
+ end
269
+
270
+ it "can be marked for destruction" do
271
+ form.marked_for_destruction?.should be_false
272
+ form.mark_for_destruction
273
+ form.marked_for_destruction?.should be_true
274
+ end
275
+
276
+ it "interprets '0' is not marked for destruction" do
277
+ form.fill({:_destroy => "0"})
278
+ form.marked_for_destruction?.should be_false
279
+ end
280
+
281
+ it "interprets 'false' is not marked for destruction" do
282
+ form.fill({:_destroy => "false"})
283
+ form.marked_for_destruction?.should be_false
284
+ end
285
+
286
+ it "interprets '1' is marked for destruction" do
287
+ form.fill({:_destroy => "1"})
288
+ form.marked_for_destruction?.should be_true
289
+ end
290
+
291
+ it "interprets 'true' is marked for destruction" do
292
+ form.fill({:_destroy => "true"})
293
+ form.marked_for_destruction?.should be_true
294
+ end
295
+
296
+ it "interprets '2' is marked for destruction" do
297
+ form.fill({:_destroy => "2"})
298
+ form.marked_for_destruction?.should be_true
299
+ end
182
300
  end
183
301
  end
184
302
  end
185
303
 
186
304
  describe "instance methods", :instance_methods => true do
305
+ describe "parent_form", :parent_form => true do
306
+ let(:form_class) do
307
+ Class.new(Module) do
308
+ include FreeForm::Property
309
+ declared_model :first_model
310
+ declared_model :second_model
311
+
312
+ property :attribute_1, :on => :first_model
313
+ property :attribute_2, :on => :first_model, :ignore_blank => true
314
+ property :attribute_3, :on => :second_model, :ignore_blank => true
315
+ property :attribute_4, :on => :second_model
316
+
317
+ def initialize(h)
318
+ h.each {|k,v| send("#{k}=",v)}
319
+ end
320
+ end
321
+ end
322
+
323
+ let(:form) do
324
+ form_class.new(
325
+ :first_model => OpenStruct.new(:attribute_1 => "first", :attribute_2 => "second"),
326
+ :second_model => OpenStruct.new(:attribute_3 => "third", :attribute_4 => "fourth"),
327
+ )
328
+ end
329
+
330
+ it "has parent_form as nil by default" do
331
+ form.parent_form.should be_nil
332
+ end
333
+
334
+ it "has can assign and reference parent_form" do
335
+ parent = Module.new
336
+ form.parent_form = parent
337
+ form.parent_form.should eq(parent)
338
+ end
339
+ end
187
340
  describe "assign_attributes", :assign_attributes => true do
188
341
  let(:form_class) do
189
342
  Class.new(Module) do