formotion 0.5.1 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. data/CHANGELOG.md +24 -0
  2. data/LIST_OF_ROW_TYPES.md +1 -1
  3. data/Rakefile +20 -5
  4. data/app/app_delegate.rb +89 -17
  5. data/examples/FormModel/.gitignore +5 -0
  6. data/examples/FormModel/Rakefile +9 -0
  7. data/examples/FormModel/app/app_delegate.rb +11 -0
  8. data/examples/FormModel/app/user.rb +18 -0
  9. data/examples/FormModel/app/users_controller.rb +52 -0
  10. data/examples/FormModel/spec/main_spec.rb +9 -0
  11. data/examples/KitchenSink/app/app_delegate.rb +2 -2
  12. data/gh-pages/assets/css/bootstrap-responsive.css +815 -0
  13. data/gh-pages/assets/css/bootstrap-responsive.min.css +9 -0
  14. data/gh-pages/assets/css/bootstrap.css +4983 -0
  15. data/gh-pages/assets/css/bootstrap.min.css +9 -0
  16. data/gh-pages/assets/css/formotion.css +117 -0
  17. data/gh-pages/assets/css/pygments.css +62 -0
  18. data/gh-pages/assets/img/glyphicons-halflings-white.png +0 -0
  19. data/gh-pages/assets/img/glyphicons-halflings.png +0 -0
  20. data/gh-pages/assets/js/bootstrap-alert.js +90 -0
  21. data/gh-pages/assets/js/bootstrap-button.js +96 -0
  22. data/gh-pages/assets/js/bootstrap-carousel.js +169 -0
  23. data/gh-pages/assets/js/bootstrap-collapse.js +157 -0
  24. data/gh-pages/assets/js/bootstrap-dropdown.js +100 -0
  25. data/gh-pages/assets/js/bootstrap-modal.js +218 -0
  26. data/gh-pages/assets/js/bootstrap-popover.js +98 -0
  27. data/gh-pages/assets/js/bootstrap-scrollspy.js +151 -0
  28. data/gh-pages/assets/js/bootstrap-tab.js +135 -0
  29. data/gh-pages/assets/js/bootstrap-tooltip.js +275 -0
  30. data/gh-pages/assets/js/bootstrap-transition.js +61 -0
  31. data/gh-pages/assets/js/bootstrap-typeahead.js +285 -0
  32. data/gh-pages/assets/js/bootstrap.js +1825 -0
  33. data/gh-pages/assets/js/bootstrap.min.js +6 -0
  34. data/gh-pages/index.html +205 -0
  35. data/lib/formotion.rb +15 -2
  36. data/lib/formotion/base.rb +5 -5
  37. data/lib/formotion/{form_controller.rb → controller/form_controller.rb} +22 -3
  38. data/lib/formotion/controller/formable_controller.rb +21 -0
  39. data/lib/formotion/form/form.rb +31 -8
  40. data/lib/formotion/form/form_delegate.rb +26 -3
  41. data/lib/formotion/model/formable.rb +78 -0
  42. data/lib/formotion/row/row.rb +54 -21
  43. data/lib/formotion/row/row_cell_builder.rb +1 -1
  44. data/lib/formotion/row_type/back_row.rb +11 -0
  45. data/lib/formotion/row_type/base.rb +42 -1
  46. data/lib/formotion/row_type/button.rb +30 -0
  47. data/lib/formotion/row_type/check_row.rb +9 -5
  48. data/lib/formotion/row_type/date_row.rb +5 -0
  49. data/lib/formotion/row_type/edit_row.rb +14 -0
  50. data/lib/formotion/row_type/image_row.rb +7 -7
  51. data/lib/formotion/row_type/options_row.rb +18 -8
  52. data/lib/formotion/row_type/slider_row.rb +14 -5
  53. data/lib/formotion/row_type/string_row.rb +17 -5
  54. data/lib/formotion/row_type/subform_row.rb +16 -0
  55. data/lib/formotion/row_type/submit_row.rb +1 -24
  56. data/lib/formotion/row_type/switch_row.rb +10 -2
  57. data/lib/formotion/row_type/template_row.rb +77 -0
  58. data/lib/formotion/row_type/text_row.rb +12 -4
  59. data/lib/formotion/section/section.rb +9 -1
  60. data/lib/formotion/version.rb +1 -1
  61. data/spec/form_spec.rb +24 -0
  62. data/spec/formable_spec.rb +100 -0
  63. data/spec/functional/formable_controller_spec.rb +47 -0
  64. data/spec/functional/image_row_spec.rb +2 -2
  65. data/spec/functional/subform_row.rb +33 -0
  66. data/spec/functional/template_row_spec.rb +57 -0
  67. data/spec/helpers/row_test_helpers.rb +26 -0
  68. data/spec/row_type/back_spec.rb +31 -0
  69. data/spec/row_type/check_spec.rb +9 -9
  70. data/spec/row_type/date_spec.rb +3 -10
  71. data/spec/row_type/email_spec.rb +1 -9
  72. data/spec/row_type/image_spec.rb +3 -12
  73. data/spec/row_type/number_spec.rb +1 -9
  74. data/spec/row_type/options_spec.rb +18 -10
  75. data/spec/row_type/phone_spec.rb +1 -9
  76. data/spec/row_type/picker_spec.rb +2 -11
  77. data/spec/row_type/slider_spec.rb +11 -10
  78. data/spec/row_type/static_spec.rb +1 -9
  79. data/spec/row_type/string_spec.rb +13 -9
  80. data/spec/row_type/subform_spec.rb +47 -0
  81. data/spec/row_type/submit_spec.rb +1 -9
  82. data/spec/row_type/switch_spec.rb +9 -9
  83. data/spec/row_type/template_spec.rb +14 -0
  84. data/spec/row_type/text_spec.rb +9 -9
  85. metadata +58 -6
@@ -0,0 +1,47 @@
1
+ class TestModel
2
+ include Formotion::Formable
3
+
4
+ attr_accessor :my_name, :my_number
5
+
6
+ form_property :my_name, :string, title: "My Name"
7
+ form_property :my_number, :number, title: "My Number", :transform => lambda { |value| value.to_i + 10 }
8
+ end
9
+
10
+ describe "FormableController" do
11
+ tests Formotion::FormableController
12
+
13
+ def controller
14
+ @model ||= TestModel.new
15
+
16
+ @controller ||= Formotion::FormableController.alloc.initWithModel(@model)
17
+ end
18
+
19
+ def string_row
20
+ @controller.form.sections.first.rows.first
21
+ end
22
+
23
+ def number_row
24
+ @controller.form.sections.first.rows.last
25
+ end
26
+
27
+ after do
28
+ (@active_row || string_row).text_field.resignFirstResponder
29
+ wait 1 do
30
+ @active_row = nil
31
+ end
32
+ end
33
+
34
+ it "should have new my_value after typing" do
35
+ @active_row = string_row
36
+ tap("My Name")
37
+ string_row.text_field.setText("Hello")
38
+ @model.my_name.should == "Hello"
39
+ end
40
+
41
+ it "should have new my_number after typing" do
42
+ @active_row = number_row
43
+ tap("My Number")
44
+ number_row.text_field.setText("10")
45
+ @model.my_number.should == 20
46
+ end
47
+ end
@@ -70,13 +70,13 @@ describe "FormController/ImageRow" do
70
70
  it "should be able to delete value" do
71
71
  image = UIImage.alloc.init
72
72
  image_row.value = image
73
- image_row.rowHeight.should > 44
73
+ image_row.row_height.should > 44
74
74
 
75
75
  tap("Photo")
76
76
 
77
77
  # Looks like view(label) doesn't scan the UIActionSheet properly, so we override it.
78
78
  tap_action_sheet("Delete")
79
- image_row.rowHeight.should == 44
79
+ image_row.row_height.should == 44
80
80
  image_row.value.should == nil
81
81
  end
82
82
  end
@@ -0,0 +1,33 @@
1
+ describe "FormController/SubformRow" do
2
+ tests Formotion::FormController
3
+
4
+ # By default, `tests` uses @controller.init
5
+ # this isn't ideal for our case, so override.
6
+ def controller
7
+ row_settings = {
8
+ title: "Goto",
9
+ type: :subform,
10
+ subform: {
11
+ title: 'Subform',
12
+ sections: [{
13
+ rows: [{
14
+ title: 'Mordor',
15
+ type: :static,
16
+ }]
17
+ }]
18
+ }
19
+ }
20
+ @form ||= Formotion::Form.new(
21
+ sections: [{
22
+ rows:[row_settings]
23
+ }])
24
+
25
+ @controller ||= Formotion::FormController.alloc.initWithForm(@form)
26
+ end
27
+
28
+ it "should goto subform when tapped" do
29
+ tap("Goto")
30
+ controller.modalViewController.should != nil
31
+ window.viewByName('Mordor').should != nil
32
+ end
33
+ end
@@ -0,0 +1,57 @@
1
+ describe "FormController/TemplateRow" do
2
+ tests Formotion::FormController
3
+
4
+ # By default, `tests` uses @controller.init
5
+ # this isn't ideal for our case, so override.
6
+ def controller
7
+ row_settings = {
8
+ title: "Add element",
9
+ key: :template,
10
+ type: :template,
11
+ value: ['Value'],
12
+ template: {
13
+ title: 'Element',
14
+ type: :string,
15
+ indented: true,
16
+ deletable: true
17
+ }
18
+ }
19
+ @form ||= Formotion::Form.new(
20
+ sections: [{
21
+ rows:[row_settings]
22
+ }])
23
+
24
+ @controller ||= Formotion::FormController.alloc.initWithForm(@form)
25
+ end
26
+
27
+ def new_row
28
+ @form.sections.first.rows[-2]
29
+ end
30
+
31
+ after do
32
+ @form = nil
33
+ @controller = nil
34
+ end
35
+
36
+ it "should insert row" do
37
+ tap("Add element")
38
+ @form.sections.first.rows.size.should == 3
39
+ end
40
+
41
+ it "should remove row" do
42
+ tap("Add element")
43
+ new_row.object.on_delete(nil, nil)
44
+ @form.sections.first.rows.size.should == 2
45
+ end
46
+
47
+ it "should render values as array" do
48
+
49
+ tap("Add element")
50
+ new_row.value = 'Value 2'
51
+
52
+ tap("Add element")
53
+ new_row.value = 'Value 3'
54
+
55
+ @form.render[:template].should == ['Value', 'Value 2', 'Value 3']
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ module Bacon
2
+ class Context
3
+ # Sets up a new @row RowType object to be reset before every test.
4
+ #
5
+ # @param row_settings is a hash of row settings or a symbol
6
+ # corresponding to a row type
7
+ # @param block is optional; the @row object is passed if given.
8
+ #
9
+ # EX
10
+ # test_row :image
11
+ # => tests the RowType::ImageRow
12
+ # test_row title: "Title", key: "some key", type: :string
13
+ # => tests the RowType::StringRow
14
+ def tests_row(row_settings, &block)
15
+ if row_settings.is_a? Symbol
16
+ type = row_settings
17
+ row_settings = { type: type, key: type, title: type.capitalize.to_s }
18
+ end
19
+ before do
20
+ @row = Formotion::Row.new(row_settings)
21
+ @row.reuse_identifier = 'test'
22
+ block && block.call(@row)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ describe "Back Row" do
2
+ tests_row :back
3
+
4
+ it "should initialize with correct settings" do
5
+ @row.object.class.should == Formotion::RowType::BackRow
6
+ end
7
+
8
+ it "should pop subform on select" do
9
+ form = FakeForm.new
10
+ @row.instance_variable_set("@section", form)
11
+ @row.object.on_select(nil, nil)
12
+ form.controller.pop_subform_called.should == true
13
+ end
14
+ end
15
+
16
+ class FakeForm
17
+ def form
18
+ self
19
+ end
20
+
21
+ def controller
22
+ @controller ||= FakeControllerClass.new
23
+ end
24
+ end
25
+
26
+ class FakeControllerClass
27
+ attr_accessor :pop_subform_called
28
+ def pop_subform
29
+ self.pop_subform_called = true
30
+ end
31
+ end
@@ -1,13 +1,5 @@
1
1
  describe "Check Row" do
2
- before do
3
- row_settings = {
4
- title: "Check",
5
- key: :check,
6
- type: :check,
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
- end
2
+ tests_row :check
11
3
 
12
4
  it "should initialize with correct settings" do
13
5
  @row.object.class.should == Formotion::RowType::CheckRow
@@ -24,4 +16,12 @@ describe "Check Row" do
24
16
  cell = @row.make_cell
25
17
  cell.accessoryType.should == UITableViewCellAccessoryCheckmark
26
18
  end
19
+
20
+ it "should bind its accessory" do
21
+ @row.value = true
22
+ cell = @row.make_cell
23
+
24
+ @row.value = false
25
+ cell.accessoryType.should == UITableViewCellAccessoryNone
26
+ end
27
27
  end
@@ -2,16 +2,9 @@ MILLENIUM = 946684672
2
2
  TIME_ZONE = NSTimeZone.timeZoneWithName "Europe/Paris"
3
3
 
4
4
  describe "Date Row" do
5
- before do
6
- row_settings = {
7
- title: "Date",
8
- key: :date,
9
- type: :date,
10
- }
11
- @row = Formotion::Row.new(row_settings)
12
- @row.reuse_identifier = 'test'
13
- @row.object.formatter.timeZone = TIME_ZONE
14
- @row.object.picker.timeZone = TIME_ZONE
5
+ tests_row :date do |row|
6
+ row.object.formatter.timeZone = TIME_ZONE
7
+ row.object.picker.timeZone = TIME_ZONE
15
8
  end
16
9
 
17
10
  it "should initialize with correct settings" do
@@ -1,13 +1,5 @@
1
1
  describe "Email Row" do
2
- before do
3
- row_settings = {
4
- title: "Email",
5
- key: :email,
6
- type: :email,
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
- end
2
+ tests_row :email
11
3
 
12
4
  it "should initialize with correct settings" do
13
5
  @row.object.class.should == Formotion::RowType::EmailRow
@@ -1,15 +1,6 @@
1
1
  describe "Image Row" do
2
- before do
3
- row_settings = {
4
- title: "Photo",
5
- key: :photo,
6
- type: :image
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
-
11
-
12
- @row.instance_eval do
2
+ tests_row :image do |row|
3
+ row.instance_eval do
13
4
  def form
14
5
  @form ||= Object.new.tap do |o|
15
6
  def o.reload_data
@@ -35,7 +26,7 @@ describe "Image Row" do
35
26
 
36
27
  @row.value = UIImage.alloc.init
37
28
 
38
- @row.rowHeight.should > 44
29
+ @row.row_height.should > 44
39
30
  image_view = cell.viewWithTag(Formotion::RowType::ImageRow::IMAGE_VIEW_TAG)
40
31
  image_view.image.nil?.should == false
41
32
  cell.accessoryView.nil?.should == true
@@ -1,13 +1,5 @@
1
1
  describe "Number Row" do
2
- before do
3
- row_settings = {
4
- title: "Number",
5
- key: :number,
6
- type: :number,
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
- end
2
+ tests_row :number
11
3
 
12
4
  it "should initialize with correct settings" do
13
5
  @row.object.class.should == Formotion::RowType::NumberRow
@@ -1,14 +1,6 @@
1
1
  describe "Options Row" do
2
- before do
3
- row_settings = {
4
- title: "Options",
5
- key: :options,
6
- type: :options,
7
- items: ['First', 'Second']
8
- }
9
- @row = Formotion::Row.new(row_settings)
10
- @row.reuse_identifier = 'test'
11
- end
2
+ tests_row title: "Options", key: :options, type: :options,
3
+ items: ["First", "Second"]
12
4
 
13
5
  it "should initialize with correct settings" do
14
6
  @row.object.class.should == Formotion::RowType::OptionsRow
@@ -34,4 +26,20 @@ describe "Options Row" do
34
26
  cell.accessoryView.selectedSegmentIndex.should == 1
35
27
  @row.value.should == 'Second'
36
28
  end
29
+
30
+ it "should bind value to control" do
31
+ @row.value = 'Second'
32
+ cell = @row.make_cell
33
+
34
+ @row.value = "First"
35
+ cell.accessoryView.selectedSegmentIndex.should == 0
36
+ end
37
+
38
+ it "should bind nil to no selected segment" do
39
+ @row.value = 'Second'
40
+ cell = @row.make_cell
41
+
42
+ @row.value = nil
43
+ cell.accessoryView.selectedSegmentIndex.should == UISegmentedControlNoSegment
44
+ end
37
45
  end
@@ -1,13 +1,5 @@
1
1
  describe "Phone Row" do
2
- before do
3
- row_settings = {
4
- title: "Phone",
5
- key: :phone,
6
- type: :phone,
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
- end
2
+ tests_row :phone
11
3
 
12
4
  it "should initialize with correct settings" do
13
5
  @row.object.class.should == Formotion::RowType::PhoneRow
@@ -1,15 +1,6 @@
1
1
  describe "Picker Row" do
2
- before do
3
- row_settings = {
4
- title: "Picker",
5
- key: :picker,
6
- type: :picker,
7
- items: ["Ruby", "Motion"],
8
- value: "Motion"
9
- }
10
- @row = Formotion::Row.new(row_settings)
11
- @row.reuse_identifier = 'test'
12
- end
2
+ tests_row title: "Picker", key: :picker, type: :picker,
3
+ items: ["Ruby", "Motion"], value: "Motion"
13
4
 
14
5
  it "should initialize with correct settings" do
15
6
  @row.object.class.should == Formotion::RowType::PickerRow
@@ -1,14 +1,6 @@
1
1
  describe "Slider Row" do
2
- before do
3
- row_settings = {
4
- title: "Slider",
5
- key: :slider,
6
- type: :slider,
7
- range: (1..100)
8
- }
9
- @row = Formotion::Row.new(row_settings)
10
- @row.reuse_identifier = 'test'
11
- end
2
+ tests_row title: "Slider", key: :slider, type: :slider,
3
+ range: (1..100)
12
4
 
13
5
  it "should initialize with correct settings" do
14
6
  @row.object.class.should == Formotion::RowType::SliderRow
@@ -28,6 +20,15 @@ describe "Slider Row" do
28
20
  @row.value.should == 50
29
21
  end
30
22
 
23
+ it "should bind to row value" do
24
+ @row.range = (50..100)
25
+ @row.value = 25
26
+ cell = @row.make_cell
27
+
28
+ @row.value = 75
29
+ cell.accessoryView.value.should == 75
30
+ end
31
+
31
32
  # Range
32
33
  it "should use default range" do
33
34
  @row.range = nil
@@ -1,13 +1,5 @@
1
1
  describe "Static Row" do
2
- before do
3
- row_settings = {
4
- title: "Static",
5
- key: :static,
6
- type: :static,
7
- }
8
- @row = Formotion::Row.new(row_settings)
9
- @row.reuse_identifier = 'test'
10
- end
2
+ tests_row :static
11
3
 
12
4
  it "should initialize with correct settings" do
13
5
  @row.object.class.should == Formotion::RowType::StaticRow