formotion 0.5.1 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +24 -0
- data/LIST_OF_ROW_TYPES.md +1 -1
- data/Rakefile +20 -5
- data/app/app_delegate.rb +89 -17
- data/examples/FormModel/.gitignore +5 -0
- data/examples/FormModel/Rakefile +9 -0
- data/examples/FormModel/app/app_delegate.rb +11 -0
- data/examples/FormModel/app/user.rb +18 -0
- data/examples/FormModel/app/users_controller.rb +52 -0
- data/examples/FormModel/spec/main_spec.rb +9 -0
- data/examples/KitchenSink/app/app_delegate.rb +2 -2
- data/gh-pages/assets/css/bootstrap-responsive.css +815 -0
- data/gh-pages/assets/css/bootstrap-responsive.min.css +9 -0
- data/gh-pages/assets/css/bootstrap.css +4983 -0
- data/gh-pages/assets/css/bootstrap.min.css +9 -0
- data/gh-pages/assets/css/formotion.css +117 -0
- data/gh-pages/assets/css/pygments.css +62 -0
- data/gh-pages/assets/img/glyphicons-halflings-white.png +0 -0
- data/gh-pages/assets/img/glyphicons-halflings.png +0 -0
- data/gh-pages/assets/js/bootstrap-alert.js +90 -0
- data/gh-pages/assets/js/bootstrap-button.js +96 -0
- data/gh-pages/assets/js/bootstrap-carousel.js +169 -0
- data/gh-pages/assets/js/bootstrap-collapse.js +157 -0
- data/gh-pages/assets/js/bootstrap-dropdown.js +100 -0
- data/gh-pages/assets/js/bootstrap-modal.js +218 -0
- data/gh-pages/assets/js/bootstrap-popover.js +98 -0
- data/gh-pages/assets/js/bootstrap-scrollspy.js +151 -0
- data/gh-pages/assets/js/bootstrap-tab.js +135 -0
- data/gh-pages/assets/js/bootstrap-tooltip.js +275 -0
- data/gh-pages/assets/js/bootstrap-transition.js +61 -0
- data/gh-pages/assets/js/bootstrap-typeahead.js +285 -0
- data/gh-pages/assets/js/bootstrap.js +1825 -0
- data/gh-pages/assets/js/bootstrap.min.js +6 -0
- data/gh-pages/index.html +205 -0
- data/lib/formotion.rb +15 -2
- data/lib/formotion/base.rb +5 -5
- data/lib/formotion/{form_controller.rb → controller/form_controller.rb} +22 -3
- data/lib/formotion/controller/formable_controller.rb +21 -0
- data/lib/formotion/form/form.rb +31 -8
- data/lib/formotion/form/form_delegate.rb +26 -3
- data/lib/formotion/model/formable.rb +78 -0
- data/lib/formotion/row/row.rb +54 -21
- data/lib/formotion/row/row_cell_builder.rb +1 -1
- data/lib/formotion/row_type/back_row.rb +11 -0
- data/lib/formotion/row_type/base.rb +42 -1
- data/lib/formotion/row_type/button.rb +30 -0
- data/lib/formotion/row_type/check_row.rb +9 -5
- data/lib/formotion/row_type/date_row.rb +5 -0
- data/lib/formotion/row_type/edit_row.rb +14 -0
- data/lib/formotion/row_type/image_row.rb +7 -7
- data/lib/formotion/row_type/options_row.rb +18 -8
- data/lib/formotion/row_type/slider_row.rb +14 -5
- data/lib/formotion/row_type/string_row.rb +17 -5
- data/lib/formotion/row_type/subform_row.rb +16 -0
- data/lib/formotion/row_type/submit_row.rb +1 -24
- data/lib/formotion/row_type/switch_row.rb +10 -2
- data/lib/formotion/row_type/template_row.rb +77 -0
- data/lib/formotion/row_type/text_row.rb +12 -4
- data/lib/formotion/section/section.rb +9 -1
- data/lib/formotion/version.rb +1 -1
- data/spec/form_spec.rb +24 -0
- data/spec/formable_spec.rb +100 -0
- data/spec/functional/formable_controller_spec.rb +47 -0
- data/spec/functional/image_row_spec.rb +2 -2
- data/spec/functional/subform_row.rb +33 -0
- data/spec/functional/template_row_spec.rb +57 -0
- data/spec/helpers/row_test_helpers.rb +26 -0
- data/spec/row_type/back_spec.rb +31 -0
- data/spec/row_type/check_spec.rb +9 -9
- data/spec/row_type/date_spec.rb +3 -10
- data/spec/row_type/email_spec.rb +1 -9
- data/spec/row_type/image_spec.rb +3 -12
- data/spec/row_type/number_spec.rb +1 -9
- data/spec/row_type/options_spec.rb +18 -10
- data/spec/row_type/phone_spec.rb +1 -9
- data/spec/row_type/picker_spec.rb +2 -11
- data/spec/row_type/slider_spec.rb +11 -10
- data/spec/row_type/static_spec.rb +1 -9
- data/spec/row_type/string_spec.rb +13 -9
- data/spec/row_type/subform_spec.rb +47 -0
- data/spec/row_type/submit_spec.rb +1 -9
- data/spec/row_type/switch_spec.rb +9 -9
- data/spec/row_type/template_spec.rb +14 -0
- data/spec/row_type/text_spec.rb +9 -9
- metadata +58 -6
@@ -1,13 +1,14 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
3
|
class SliderRow < Base
|
4
|
+
include BW::KVO
|
4
5
|
|
5
6
|
SLIDER_VIEW_TAG = 1200
|
6
7
|
|
7
8
|
def build_cell(cell)
|
8
9
|
cell.selectionStyle = UITableViewCellSelectionStyleNone
|
9
10
|
slideView = UISlider.alloc.initWithFrame(CGRectZero)
|
10
|
-
cell.accessoryView = slideView
|
11
|
+
cell.accessoryView = cell.editingAccessoryView = slideView
|
11
12
|
row.range ||= (1..10)
|
12
13
|
slideView.minimumValue = row.range.first
|
13
14
|
slideView.maximumValue = row.range.last
|
@@ -16,9 +17,17 @@ module Formotion
|
|
16
17
|
slideView.accessibilityLabel = row.title + " Slider"
|
17
18
|
|
18
19
|
slideView.when(UIControlEventValueChanged) do
|
19
|
-
|
20
|
+
break_with_semaphore do
|
21
|
+
row.value = slideView.value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
observe(self.row, "value") do |old_value, new_value|
|
25
|
+
break_with_semaphore do
|
26
|
+
slideView.setValue(row.value, animated:false)
|
27
|
+
end
|
20
28
|
end
|
21
29
|
|
30
|
+
|
22
31
|
cell.swizzle(:layoutSubviews) do
|
23
32
|
def layoutSubviews
|
24
33
|
old_layoutSubviews
|
@@ -29,9 +38,9 @@ module Formotion
|
|
29
38
|
|
30
39
|
field_frame = formotion_field.frame
|
31
40
|
field_frame.origin.y = 10
|
32
|
-
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width +
|
33
|
-
field_frame.size.width = self.frame.size.width - field_frame.origin.x -
|
34
|
-
field_frame.size.height = self.frame.size.height -
|
41
|
+
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + FIELD_BUFFER
|
42
|
+
field_frame.size.width = self.frame.size.width - field_frame.origin.x - FIELD_BUFFER
|
43
|
+
field_frame.size.height = self.frame.size.height - FIELD_BUFFER
|
35
44
|
formotion_field.frame = field_frame
|
36
45
|
end
|
37
46
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
3
|
class StringRow < Base
|
4
|
+
include BW::KVO
|
4
5
|
|
5
6
|
# The new UITextField in a UITableViewCell
|
6
7
|
# will be assigned this tag, if applicable.
|
@@ -21,8 +22,11 @@ module Formotion
|
|
21
22
|
field = UITextField.alloc.initWithFrame(CGRectZero)
|
22
23
|
field.tag = TEXT_FIELD_TAG
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
observe(self.row, "value") do |old_value, new_value|
|
26
|
+
break_with_semaphore do
|
27
|
+
update_text_field(new_value)
|
28
|
+
end
|
29
|
+
end
|
26
30
|
|
27
31
|
field.clearButtonMode = UITextFieldViewModeWhileEditing
|
28
32
|
field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
|
@@ -47,13 +51,15 @@ module Formotion
|
|
47
51
|
formotion_field.sizeToFit
|
48
52
|
|
49
53
|
field_frame = formotion_field.frame
|
50
|
-
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width +
|
54
|
+
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + FIELD_BUFFER
|
51
55
|
field_frame.origin.y = ((self.frame.size.height - field_frame.size.height) / 2.0).round
|
52
|
-
field_frame.size.width = self.frame.size.width - field_frame.origin.x -
|
56
|
+
field_frame.size.width = self.frame.size.width - field_frame.origin.x - FIELD_BUFFER
|
53
57
|
formotion_field.frame = field_frame
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
61
|
+
field.placeholder = row.placeholder
|
62
|
+
field.text = row.value.to_s
|
57
63
|
cell.addSubview(field)
|
58
64
|
field
|
59
65
|
|
@@ -100,13 +106,19 @@ module Formotion
|
|
100
106
|
end
|
101
107
|
|
102
108
|
def on_change(text_field)
|
103
|
-
|
109
|
+
break_with_semaphore do
|
110
|
+
row.value = text_field.text
|
111
|
+
end
|
104
112
|
end
|
105
113
|
|
106
114
|
def on_select(tableView, tableViewDelegate)
|
107
115
|
row.text_field.becomeFirstResponder
|
108
116
|
end
|
109
117
|
|
118
|
+
# Used when row.value changes
|
119
|
+
def update_text_field(new_value)
|
120
|
+
self.row.text_field.text = new_value
|
121
|
+
end
|
110
122
|
end
|
111
123
|
end
|
112
124
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Formotion
|
2
|
+
module RowType
|
3
|
+
class SubformRow < Base
|
4
|
+
|
5
|
+
def build_cell(cell)
|
6
|
+
cell.accessoryType = cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator
|
7
|
+
end
|
8
|
+
|
9
|
+
def on_select(tableView, tableViewDelegate)
|
10
|
+
subform = row.subform.to_form
|
11
|
+
row.form.controller.push_subform(subform)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,29 +1,6 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
|
-
class SubmitRow <
|
4
|
-
|
5
|
-
def submit_button?
|
6
|
-
true
|
7
|
-
end
|
8
|
-
|
9
|
-
# Does a clever little trick to override #layoutSubviews
|
10
|
-
# for just this one UITableViewCell object, in order to
|
11
|
-
# center it's labels horizontally.
|
12
|
-
def build_cell(cell)
|
13
|
-
cell.swizzle(:layoutSubviews) do
|
14
|
-
def layoutSubviews
|
15
|
-
old_layoutSubviews
|
16
|
-
|
17
|
-
center = lambda {|frame, dimen|
|
18
|
-
((self.frame.size.send(dimen) - frame.size.send(dimen)) / 2.0)
|
19
|
-
}
|
20
|
-
|
21
|
-
self.textLabel.center = CGPointMake(self.frame.size.width / 2 - 10, self.textLabel.center.y)
|
22
|
-
self.detailTextLabel.center = CGPointMake(self.frame.size.width / 2 - 10, self.detailTextLabel.center.y)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
nil
|
26
|
-
end
|
3
|
+
class SubmitRow < Button
|
27
4
|
|
28
5
|
def on_select(tableView, tableViewDelegate)
|
29
6
|
tableViewDelegate.submit
|
@@ -1,15 +1,23 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
3
|
class SwitchRow < Base
|
4
|
+
include BW::KVO
|
4
5
|
|
5
6
|
def build_cell(cell)
|
6
7
|
cell.selectionStyle = UITableViewCellSelectionStyleNone
|
7
8
|
switchView = UISwitch.alloc.initWithFrame(CGRectZero)
|
8
9
|
switchView.accessibilityLabel = row.title + " Switch"
|
9
|
-
cell.accessoryView = switchView
|
10
|
+
cell.accessoryView = cell.editingAccessoryView = switchView
|
10
11
|
switchView.setOn(row.value || false, animated:false)
|
11
12
|
switchView.when(UIControlEventValueChanged) do
|
12
|
-
|
13
|
+
break_with_semaphore do
|
14
|
+
row.value = switchView.isOn
|
15
|
+
end
|
16
|
+
end
|
17
|
+
observe(self.row, "value") do |old_value, new_value|
|
18
|
+
break_with_semaphore do
|
19
|
+
switchView.setOn(row.value || false, animated: false)
|
20
|
+
end
|
13
21
|
end
|
14
22
|
nil
|
15
23
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Define template row:
|
2
|
+
# {
|
3
|
+
# title: "Add nickname",
|
4
|
+
# key: :nicknames,
|
5
|
+
# type: :template,
|
6
|
+
# template: {
|
7
|
+
# title: 'Nickname %{index}',
|
8
|
+
# type: :string
|
9
|
+
# }
|
10
|
+
# value: ['Samy', 'Pamy']
|
11
|
+
# }
|
12
|
+
|
13
|
+
# row.value = ['Samy', 'Pamy']
|
14
|
+
module Formotion
|
15
|
+
module RowType
|
16
|
+
class TemplateRow < Base
|
17
|
+
|
18
|
+
def cellEditingStyle
|
19
|
+
UITableViewCellEditingStyleInsert
|
20
|
+
end
|
21
|
+
|
22
|
+
def indentWhileEditing?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_cell(cell)
|
27
|
+
cell.selectionStyle = UITableViewCellSelectionStyleBlue
|
28
|
+
@add_button ||= begin
|
29
|
+
button = UIButton.buttonWithType(UIButtonTypeContactAdd)
|
30
|
+
button.when(UIControlEventTouchUpInside) do
|
31
|
+
self.on_select(nil, nil)
|
32
|
+
end
|
33
|
+
button
|
34
|
+
end
|
35
|
+
cell.accessoryView = @add_button
|
36
|
+
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_select(tableView, tableViewDelegate)
|
41
|
+
on_insert(tableView, tableViewDelegate)
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_insert(tableView, tableViewDelegate)
|
45
|
+
@template_index = row.section.rows.count
|
46
|
+
new_row = build_new_row
|
47
|
+
move_row_in_list(new_row)
|
48
|
+
insert_row(new_row)
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_new_row(options = {})
|
52
|
+
# build row
|
53
|
+
new_row = row.section.create_row(row.template.merge(options))
|
54
|
+
new_row.remove_on_delete = true
|
55
|
+
new_row.template_parent = self.row
|
56
|
+
new_row
|
57
|
+
end
|
58
|
+
|
59
|
+
def move_row_in_list(new_row)
|
60
|
+
# move to top
|
61
|
+
row.section.rows.pop
|
62
|
+
row.section.rows.insert(@template_index - 1, new_row)
|
63
|
+
|
64
|
+
# reset indexes
|
65
|
+
row.section.refresh_row_indexes
|
66
|
+
end
|
67
|
+
|
68
|
+
def insert_row(new_row)
|
69
|
+
index_path = NSIndexPath.indexPathForRow(new_row.index, inSection:row.section.index)
|
70
|
+
tableView.beginUpdates
|
71
|
+
tableView.insertRowsAtIndexPaths [index_path], withRowAnimation:UITableViewRowAnimationBottom
|
72
|
+
tableView.endUpdates
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
3
|
class TextRow < Base
|
4
|
+
include BW::KVO
|
4
5
|
|
5
6
|
TEXT_VIEW_TAG=1000
|
6
7
|
|
@@ -30,8 +31,15 @@ module Formotion
|
|
30
31
|
true
|
31
32
|
end
|
32
33
|
|
34
|
+
observe(self.row, "value") do |old_value, new_value|
|
35
|
+
break_with_semaphore do
|
36
|
+
field.text = row.value
|
37
|
+
end
|
38
|
+
end
|
33
39
|
field.on_change do |text_field|
|
34
|
-
|
40
|
+
break_with_semaphore do
|
41
|
+
row.value = text_field.text
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
field.on_end do |text_field|
|
@@ -52,9 +60,9 @@ module Formotion
|
|
52
60
|
|
53
61
|
field_frame = formotion_field.frame
|
54
62
|
field_frame.origin.y = 10
|
55
|
-
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width +
|
56
|
-
field_frame.size.width = self.frame.size.width - field_frame.origin.x -
|
57
|
-
field_frame.size.height = self.frame.size.height -
|
63
|
+
field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + FIELD_BUFFER
|
64
|
+
field_frame.size.width = self.frame.size.width - field_frame.origin.x - FIELD_BUFFER
|
65
|
+
field_frame.size.height = self.frame.size.height - FIELD_BUFFER
|
58
66
|
formotion_field.frame = field_frame
|
59
67
|
end
|
60
68
|
end
|
@@ -51,6 +51,8 @@ module Formotion
|
|
51
51
|
end
|
52
52
|
row.section = self
|
53
53
|
row.index = self.rows.count
|
54
|
+
# dont move to after the appending.
|
55
|
+
row.after_create
|
54
56
|
self.rows << row
|
55
57
|
row
|
56
58
|
end
|
@@ -100,8 +102,14 @@ module Formotion
|
|
100
102
|
nil
|
101
103
|
end
|
102
104
|
|
105
|
+
def refresh_row_indexes
|
106
|
+
rows.each_with_index do |row, index|
|
107
|
+
row.index = index
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
103
111
|
#########################
|
104
|
-
# Retreiving data
|
112
|
+
# Retreiving data
|
105
113
|
def to_hash
|
106
114
|
h = super
|
107
115
|
h[:rows] = self.rows.collect {|row| row.to_hash}
|
data/lib/formotion/version.rb
CHANGED
data/spec/form_spec.rb
CHANGED
@@ -68,6 +68,30 @@ describe "Forms" do
|
|
68
68
|
@form.render[:email].should == 'something@email.com'
|
69
69
|
end
|
70
70
|
|
71
|
+
it "render with subforms works correctly" do
|
72
|
+
@form = Formotion::Form.new(sections: [{
|
73
|
+
rows: [{
|
74
|
+
type: :subform,
|
75
|
+
key: :subform,
|
76
|
+
subform: {
|
77
|
+
sections: [{
|
78
|
+
rows: [{
|
79
|
+
key: :email,
|
80
|
+
type: :email,
|
81
|
+
editable: true,
|
82
|
+
title: 'Email'
|
83
|
+
}]
|
84
|
+
}]
|
85
|
+
}
|
86
|
+
}]}])
|
87
|
+
|
88
|
+
subform = @form.sections[0].rows[0].subform.to_form
|
89
|
+
row = subform.sections[0].rows[0]
|
90
|
+
row.value = 'something@email.com'
|
91
|
+
|
92
|
+
@form.render[:subform][:email].should == 'something@email.com'
|
93
|
+
end
|
94
|
+
|
71
95
|
it "hashifying should be same as input" do
|
72
96
|
h = {
|
73
97
|
sections: [{
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class FormableTestModel
|
2
|
+
def self.the_transform
|
3
|
+
@transform ||= lambda { |value| value.to_i + 10 }
|
4
|
+
end
|
5
|
+
|
6
|
+
include Formotion::Formable
|
7
|
+
|
8
|
+
attr_accessor :my_name, :my_number
|
9
|
+
|
10
|
+
form_property :my_name, :string, title: "My Name"
|
11
|
+
form_property :my_number, :number, title: "My Number", :transform => the_transform
|
12
|
+
|
13
|
+
form_title "Custom Title"
|
14
|
+
|
15
|
+
def on_submit
|
16
|
+
@submitted = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "Formotion::Formable" do
|
21
|
+
it "form_properties should have correct structure" do
|
22
|
+
FormableTestModel.form_properties.should == [{
|
23
|
+
property: :my_name, row_type: :string, title: "My Name"
|
24
|
+
}, {
|
25
|
+
property: :my_number, row_type: :number, title: "My Number", :transform => FormableTestModel.the_transform
|
26
|
+
}]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set form_title" do
|
30
|
+
FormableTestModel.form_title.should == "Custom Title"
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".to_form" do
|
34
|
+
it "should have correct values" do
|
35
|
+
comparison_form = Formotion::Form.new({
|
36
|
+
title: "Custom Title",
|
37
|
+
sections: [{
|
38
|
+
rows: [{
|
39
|
+
title: "My Name",
|
40
|
+
key: :my_name,
|
41
|
+
type: :string,
|
42
|
+
value: nil
|
43
|
+
}, {
|
44
|
+
title: "My Number",
|
45
|
+
key: :my_number,
|
46
|
+
type: :number,
|
47
|
+
value: nil
|
48
|
+
}]
|
49
|
+
}]
|
50
|
+
})
|
51
|
+
|
52
|
+
model = FormableTestModel.new
|
53
|
+
model.to_form.to_hash.should == comparison_form.to_hash
|
54
|
+
|
55
|
+
model.my_name = "Clay"
|
56
|
+
model.my_number = 123
|
57
|
+
|
58
|
+
comparison_form = Formotion::Form.new({
|
59
|
+
title: "Custom Title",
|
60
|
+
sections: [{
|
61
|
+
rows: [{
|
62
|
+
title: "My Name",
|
63
|
+
key: :my_name,
|
64
|
+
type: :string,
|
65
|
+
value: "Clay"
|
66
|
+
}, {
|
67
|
+
title: "My Number",
|
68
|
+
key: :my_number,
|
69
|
+
type: :number,
|
70
|
+
value: 123
|
71
|
+
}]
|
72
|
+
}]
|
73
|
+
})
|
74
|
+
|
75
|
+
model.to_form.to_hash.should == comparison_form.to_hash
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have transformed render values" do
|
79
|
+
comparison_render = {
|
80
|
+
my_name: "Clay",
|
81
|
+
my_number: 133
|
82
|
+
}
|
83
|
+
|
84
|
+
model = FormableTestModel.new
|
85
|
+
model.my_name = "Clay"
|
86
|
+
model.my_number = 113
|
87
|
+
|
88
|
+
form = model.to_form
|
89
|
+
form.sections[0].rows[1].value = 123
|
90
|
+
|
91
|
+
form.render.should == comparison_render
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have correct submit" do
|
95
|
+
model = FormableTestModel.new
|
96
|
+
model.to_form.submit
|
97
|
+
model.instance_variable_get("@submitted").should == true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|