motion_model 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 2012-12-30: Added Formotion module. This allows for tighter integration with Formotion
2
+ Changed options for columns such that any arbitrary values can be inserted
3
+ allowing for future expansion.
4
+
5
+ 2012-12-14: Added lots of framework to validations
6
+ Added validations for length, format, email, presence
7
+ Added array type (thanks justinmcp)
8
+
1
9
  2012-12-07: Added MIT license file.
2
10
  InputHelpers: Whitespace cleanup. Fixed keyboard show/hide to scroll to correct position.
3
11
  MotionModel::Column: Whitespace cleanup, added code to support cascading delete (:dependent => :destroy)
data/README.md CHANGED
@@ -19,15 +19,12 @@ are:
19
19
  counting.
20
20
 
21
21
  - validatable.rb: Provides a basic validation framework for any
22
- arbitrary class. Right now, it can only validate for presence,
23
- but expect that to change soon.
22
+ arbitrary class. You can also create custom validations to suit
23
+ your app's unique needs.
24
24
 
25
- - input_helpers: Hooking an array up to a data form, populating
26
- it, and retrieving the data afterwards can be a bunch of code.
27
- Not something I'd like to write more often that I have to. These
28
- helpers are certainly not the focus of this release, but
29
- I am using these in an app to create Apple-like input forms in
30
- static tables.
25
+ - input_helpers: Hooking a collection up to a data form, populating
26
+ the form, and retrieving the data afterwards can be a bunch of code.
27
+ Not something I'd like to write more often that I have to.
31
28
 
32
29
  MotionModel is MIT licensed, which means you can pretty much do whatever
33
30
  you like with it. See the LICENSE file in this project.
@@ -94,12 +91,12 @@ class Task
94
91
  end
95
92
  ```
96
93
 
97
- You can also include the `Validations` module to get field validation. For example:
94
+ You can also include the `Validatable` module to get field validation. For example:
98
95
 
99
96
  ```ruby
100
97
  class Task
101
98
  include MotionModel::Model
102
- include MotionModel::Validations
99
+ include MotionModel::Validatable
103
100
 
104
101
  columns :name => :string,
105
102
  :description => :string,
@@ -131,6 +128,7 @@ a_task.due_date = '2012-09-19' # due_date is cast to NSDate
131
128
  Currently supported types are:
132
129
 
133
130
  * `:string`
131
+ * `text`
134
132
  * `:boolean`, `:bool`
135
133
  * `:int`, `:integer`
136
134
  * `:float`, `:double`
@@ -452,10 +450,56 @@ Core Extensions
452
450
  Again, a reversing rule is required for both singularize and
453
451
  pluralize to work properly.
454
452
 
455
- Things In The Pipeline
453
+ Experimental: Formotion Support
456
454
  ----------------------
457
455
 
458
- - Adding validations and custom validations
456
+ MotionModel now has support for the cool [Formotion gem](https://github.com/clayallsopp/formotion).
457
+ Note that the Formotion project on GitHub appears to be way ahead of the gem on Rubygems, so you
458
+ might want to build it yourself if you want the latest gee-whiz features (like `:picker_type`, as
459
+ I've shown in this example).
460
+
461
+ This feature is extremely experimental, but here's how it works:
462
+
463
+ ```ruby
464
+ class Event
465
+ include MotionModel::Model
466
+ include MotionModel::Formotion # <== Formotion support
467
+
468
+ columns :name => :string,
469
+ :date => {:type => :date, :formotion => {:picker_type => :date_time}},
470
+ :location => :string
471
+ end
472
+ ```
473
+
474
+ This declares the class. The only difference is that you include `MotionModel::Formotion`.
475
+ If you want to pass additional information on to Formotion, simply include it in the
476
+ `:formotion` hash as shown above.
477
+
478
+ MotionModel has sensible defaults for each type supported, so any field of `:date`
479
+ type will default to a date picker in the Formotion form. However, if you want it
480
+ to be a string for some reason, just pass in:
481
+
482
+ ```ruby
483
+ :date => {:type => :date, :formotion => {:type => :string}}
484
+ ```
485
+
486
+ To initialize a form from a model in your controller:
487
+
488
+ ```ruby
489
+ @form = Formotion::Form.new(@event.to_formotion('event details'))
490
+ @form_controller = MyFormController.alloc.initWithForm(@form)
491
+ ```
492
+
493
+ The magic is in: `MotionModel::Model#to_formotion(section_header)`.
494
+
495
+ and on the flip side you do something like this in your submit handler:
496
+
497
+ ```ruby
498
+ @event.from_formotion!(data)
499
+ ```
500
+
501
+ This performs sets on each field. You'll, of course, want to check your
502
+ validations before dismissing the form.
459
503
 
460
504
  Problems/Comments
461
505
  ------------------
@@ -9,8 +9,14 @@ module MotionModel
9
9
  def initialize(name = nil, type = nil, options = {})
10
10
  @name = name
11
11
  @type = type
12
- @default = options[:default]
13
- @destroy = options[:dependent]
12
+ raise RuntimeError.new "columns need a type declared." if type.nil?
13
+ @default = options.delete :default
14
+ @destroy = options.delete :dependent
15
+ @options = options
16
+ end
17
+
18
+ def options
19
+ @options
14
20
  end
15
21
 
16
22
  def classify
@@ -264,7 +264,7 @@ module MotionModel
264
264
  when Symbol, String
265
265
  add_field(name, options)
266
266
  when Hash
267
- add_field(name, options[:type], :default => options[:default])
267
+ add_field(name, options.delete(:type), options)
268
268
  else
269
269
  raise ArgumentError.new("arguments to `columns' must be a symbol, a hash, or a hash of hashes.")
270
270
  end
@@ -485,6 +485,18 @@ module MotionModel
485
485
  self.class.type(column_name)
486
486
  end
487
487
 
488
+ # Options hash for column, excluding the core
489
+ # options such as type, default, etc.
490
+ #
491
+ # Options are completely arbitrary so you can
492
+ # stuff anything in this hash you want. For
493
+ # example:
494
+ #
495
+ # columns :date => {:type => :date, :formotion => {:picker_type => :date_time}}
496
+ def options(column_name)
497
+ column_named(column_name).options
498
+ end
499
+
488
500
  # True if this object responds to the method or
489
501
  # property, otherwise false.
490
502
  alias_method :old_respond_to?, :respond_to?
@@ -513,9 +525,7 @@ module MotionModel
513
525
  end
514
526
 
515
527
  def initialize_data_columns(column, options) #nodoc
516
- options[column] ||= self.class.default(column)
517
- cast_value = cast_to_type(column, options[column])
518
- @data[column] = cast_value
528
+ self.send("#{column}=".to_sym, options[column] || self.class.default(column))
519
529
  end
520
530
 
521
531
  def collection #nodoc
@@ -19,7 +19,14 @@ module MotionModel
19
19
  end
20
20
 
21
21
  def cast_to_date(arg)
22
- arg.is_a?(NSDate) ? arg : NSDate.dateWithNaturalLanguageString(arg, locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
22
+ case arg
23
+ when String
24
+ return NSDate.dateWithNaturalLanguageString(arg.gsub('-','/'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
25
+ when Time
26
+ return NSDate.dateWithNaturalLanguageString(arg.strftime('%Y/%m/%d %H:%M'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
27
+ else
28
+ return arg
29
+ end
23
30
  end
24
31
 
25
32
  def cast_to_array(arg)
@@ -35,6 +42,7 @@ module MotionModel
35
42
  when :int, :integer, :belongs_to_id then cast_to_integer(arg)
36
43
  when :float, :double then cast_to_float(arg)
37
44
  when :date then cast_to_date(arg)
45
+ when :text then arg.to_s
38
46
  when :array then cast_to_array(arg)
39
47
  else
40
48
  raise ArgumentError.new("type #{column_name} : #{type(column_name)} is not possible to cast.")
@@ -1,3 +1,3 @@
1
1
  module MotionModel
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -0,0 +1,22 @@
1
+ class ModelWithOptions
2
+ include MotionModel::Model
3
+
4
+ columns :date => {:type => :date, :formotion => {:picker_type => :date_time}}
5
+ end
6
+
7
+ describe "column options" do
8
+ it "accepts the hash form of column declaration" do
9
+ lambda{ModelWithOptions.new}.should.not.raise
10
+ end
11
+
12
+ it "retrieves non-nil options for a column declaration" do
13
+ instance = ModelWithOptions.new
14
+ instance.options(:date).should.not.be.nil
15
+ end
16
+
17
+ it "retrieves correct options for a column declaration" do
18
+ instance = ModelWithOptions.new
19
+ instance.options(:date)[:formotion].should.not.be.nil
20
+ instance.options(:date)[:formotion][:picker_type].should == :date_time
21
+ end
22
+ end
data/spec/date_spec.rb ADDED
@@ -0,0 +1,13 @@
1
+ describe "time conversions" do
2
+ it "NSDate and Time should agreee on minutes since epoch" do
3
+ t = Time.new
4
+ d = NSDate.dateWithTimeIntervalSince1970(t.to_f)
5
+ t.to_f.should == d.timeIntervalSince1970
6
+ end
7
+
8
+ it "Parsing '3/18/12 @ 7:00 PM' With Natural Language should work right" do
9
+ NSDate.dateWithNaturalLanguageString('3/18/12 @ 7:00 PM'.gsub('-','/'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation).
10
+ strftime("%m-%d-%Y | %I:%M %p").
11
+ should == "03-18-2012 | 07:00 PM"
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ class ModelWithOptions
2
+ include MotionModel::Model
3
+ include MotionModel::Formotion
4
+
5
+ columns :name => :string,
6
+ :date => {:type => :date, :formotion => {:picker_type => :date_time}},
7
+ :location => :string
8
+ end
9
+
10
+ describe "formotion" do
11
+ before do
12
+ @subject = ModelWithOptions.create(:name => 'get together', :date => '12-11-13 @ 9:00 PM', :location => 'my house')
13
+ end
14
+
15
+ it "generates a formotion hash" do
16
+ @subject.to_formotion.should.not.be.nil
17
+ end
18
+
19
+ it "has the correct section title" do
20
+ @subject.to_formotion('test section')[:sections].first[:title].should == 'test section'
21
+ end
22
+
23
+ it "has 3 rows" do
24
+ @subject.to_formotion('test section')[:sections].first[:rows].length.should == 3
25
+ end
26
+
27
+ it "binds data from rendered form into model fields" do
28
+ @subject.from_formotion!({:name => '007 Reunion', :date => '3-3-13', :location => "Q's Lab"})
29
+ @subject.name.should == '007 Reunion'
30
+ @subject.date.strftime("%Y-%d-%d %H:%M:%S").should == '2013-03-03 12:00:00'
31
+ @subject.location.should == "Q's Lab"
32
+ end
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-15 00:00:00.000000000 Z
12
+ date: 2013-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bubble-wrap
@@ -52,8 +52,11 @@ files:
52
52
  - lib/motion_model/version.rb
53
53
  - motion_model.gemspec
54
54
  - spec/cascading_delete_spec.rb
55
+ - spec/column_options_spec.rb
56
+ - spec/date_spec.rb
55
57
  - spec/ext_spec.rb
56
58
  - spec/finder_spec.rb
59
+ - spec/formotion_spec.rb
57
60
  - spec/model_casting_spec.rb
58
61
  - spec/model_hook_spec.rb
59
62
  - spec/model_spec.rb
@@ -87,8 +90,11 @@ specification_version: 3
87
90
  summary: Simple model and validation mixins for RubyMotion
88
91
  test_files:
89
92
  - spec/cascading_delete_spec.rb
93
+ - spec/column_options_spec.rb
94
+ - spec/date_spec.rb
90
95
  - spec/ext_spec.rb
91
96
  - spec/finder_spec.rb
97
+ - spec/formotion_spec.rb
92
98
  - spec/model_casting_spec.rb
93
99
  - spec/model_hook_spec.rb
94
100
  - spec/model_spec.rb