motion_model 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ 2013-05-21: Added different method of converting from String to date using
2
+ iOS DataDetector instead of dateFromNaturalLanguageString.
3
+
1
4
  2013-04-13: WARNING: Possible breaking change. Hook methods changed to send
2
5
  affected object. So, if you have:
3
6
 
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rake"
4
+ gem "bubble-wrap"
4
5
  gem "motion-stump", '~>0.2'
data/README.md CHANGED
@@ -20,6 +20,7 @@ MotionModel is MIT licensed, which means you can pretty much do whatever
20
20
  you like with it. See the LICENSE file in this project.
21
21
 
22
22
  * [Getting Going](#getting-going)
23
+ * [Bugs, Features, and Issues, Oh My!](#bugs-features-and-issues-oh-my)
23
24
  * [What Model Can Do](#what-model-can-do)
24
25
  * [Model Data Types](#model-data-types)
25
26
  * [Validation Methods](#validation-methods)
@@ -32,11 +33,40 @@ you like with it. See the LICENSE file in this project.
32
33
  * [Problems/Comments](#problemscomments)
33
34
  * [Submissions/Patches](#submissionspatches)
34
35
 
36
+ ## Bugs, Features, and Issues, Oh My!
37
+
38
+ The reason this is up front here is that in order to respond to your issues
39
+ we need you to help us out by reading these guidelines. You can also look at
40
+ [Submissions/Patches](#submissionspatches) near the bottom of this README
41
+ which restates a bit of this.
42
+
43
+ That said, all software has bugs, and anyone who thinks otherwise probably is smarter than I am. There are going to be edge cases or cases that our tests don't cover. And that's why open source is great: other people will run into issues we can fix. Other people will have needs we don't have but that are of general utility. And so on.
44
+
45
+ But… fair is fair. We would make the following requests of you:
46
+
47
+ * Debug the code as far as you can. Obviously, there are times when you just won't be able to see what's wrong or where there's some squirrely interaction with RubyMotion.
48
+ * If you are comfortable with the MotionModel code, please try to write a spec that makes it fail and submit a pull request with that failing spec. The isolated test case helps us narrow down what changed and to know when we have the issue fixed. Two things make this even better:
49
+ 1. Our specs become more comprehensive; and
50
+ 2. If the issue is an interaction between MotionModel and RubyMotion, it's easier to pass along to HipByte and have a spec they can use for a quick hitting test case. Even better, fix the bug and submit that fix *and* the spec in a pull request.
51
+ * If you are not comfortable with the MotionModel code, then go ahead and describe the issue in as much detail as possible, including backtraces from the debugger, if appropriate.
52
+
53
+ Now, I've belabored the point about bug reporting enough. The point is, if you possibly can, write a spec.
54
+
55
+ Issues: Please mark your issues as questions or feature requests, depending on which they are. We'll do all we can to review them and answer questions as quickly as possible. For feature requests, you really can implement the feature in many cases and then submit a pull request. If not, we'll leave it open for consideration in future releases.
56
+
57
+ ### Summary
58
+
59
+ Bugs: Please write a failing spec
60
+
61
+ Issues: Please mark them as question or request
62
+
35
63
  Changes for Existing Users to Be Aware Of
36
64
  =================
37
65
 
38
66
  Please see the CHANGELOG for update on changes.
39
67
 
68
+ Version 0.4.4 is the first version to be gem-compatible with RubyMotion 2.0
69
+
40
70
  Version 0.3.8 to 0.4.0 is a minor version bump, not a patch version. Upgrading
41
71
  to 0.4.0 *will break existing code*. To update your code, simply insert the following line:
42
72
 
@@ -645,7 +675,7 @@ To initialize a form from a model in your controller:
645
675
  @form_controller = MyFormController.alloc.initWithForm(@form)
646
676
  ```
647
677
 
648
- The magic is in: `MotionModel::Model#to_formotion(section_header)`.
678
+ The magic is in: `MotionModel::Model#to_formotion(form_title)`.
649
679
 
650
680
  The auto_date fields `created_at` and `updated_at` are not sent to
651
681
  Formotion by default. If you want them sent to Formotion, set the
@@ -664,6 +694,33 @@ On the flip side you do something like this in your Formotion submit handler:
664
694
  This performs sets on each field. You'll, of course, want to check your
665
695
  validations before dismissing the form.
666
696
 
697
+ Moreover, Formotion support allows you to split one model fields in sections.
698
+ By default all fields are put in a single untitled section. Here is a complete
699
+ example:
700
+
701
+ ```ruby
702
+ class Event
703
+ include MotionModel::Model
704
+ include MotionModel::Formotion # <== Formotion support
705
+
706
+ columns :name => :string,
707
+ :date => {:type => :date, :formotion => {:picker_type => :date_time}},
708
+ :location => {:type => :string, :formotion => {:section => :address}}
709
+
710
+ has_formotion_sections :address => {:title => "Address"}
711
+ end
712
+ ```
713
+
714
+ This will create a form with the `name` and `date` fields presented first, then a
715
+ section titled 'Address' will contain the `location` field.
716
+
717
+ If you want to add a title to the first section, provide a :first_section_title
718
+ argument to `to_formotion`:
719
+
720
+ ```ruby
721
+ @form = Formotion::Form.new(@event.to_formotion('event details', true, 'First Section Title'))
722
+ ```
723
+
667
724
  Problems/Comments
668
725
  ------------------
669
726
 
data/Rakefile CHANGED
@@ -1,14 +1,16 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require "bundler/gem_tasks"
3
3
  $:.unshift("/Library/RubyMotion/lib")
4
- require 'motion/project'
4
+ require 'motion/project/template/ios'
5
5
  require 'bundler'
6
6
  Bundler.require
7
7
 
8
+ $:.unshift(File.expand_path('../lib', __FILE__))
9
+ require 'motion_model'
10
+
8
11
  Motion::Project::App.setup do |app|
9
12
  # Use `rake config' to see complete project settings.
10
13
  app.name = 'MotionModel'
11
14
  app.delegate_class = 'FakeDelegate'
12
- app.files = Dir.glob('./lib/motion_model/**/*.rb') + app.files
13
15
  app.files = (app.files + Dir.glob('./app/**/*.rb')).uniq
14
16
  end
data/lib/motion_model.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  Motion::Project::App.setup do |app|
2
- Dir.glob(File.join(File.dirname(__FILE__), "motion_model/**/*.rb")).each do |file|
2
+ Dir.glob(File.join(File.expand_path('../../motion/**/*.rb', __FILE__))).each do |file|
3
3
  app.files.unshift(file)
4
4
  end
5
5
  end
@@ -0,0 +1,66 @@
1
+ module DateParser
2
+ # Parse a date string: E.g.:
3
+ #
4
+ # DateParser.parse_date "There is a date in here tomorrow at 9:00 AM"
5
+ #
6
+ # => 2013-02-20 09:00:00 -0800
7
+ def self.parse_date(date_string)
8
+ detect(date_string).first.date
9
+ end
10
+
11
+ # Parse time zone from date
12
+ #
13
+ # ateParser.parse_date "There is a date in here tomorrow at 9:00 AM EDT"
14
+ #
15
+ # Caveat: This is implemented per Apple documentation. I've never really
16
+ # seen it work.
17
+ def self.parse_time_zone(date_string)
18
+ detect(date_string).first.timeZone
19
+ end
20
+
21
+ # Parse a date string: E.g.:
22
+ #
23
+ # SugarCube::DateParser.parse_date "You have a meeting from 9:00 AM to 3:00 PM"
24
+ #
25
+ # => 21600.0
26
+ #
27
+ # Divide by 3600.0 to get number of hours duration.
28
+ def self.parse_duration(date_string)
29
+ detect(date_string).first.send(:duration)
30
+ end
31
+
32
+ # Parse a date into a raw match array for further processing
33
+ def self.match(date_string)
34
+ detect(date_string)
35
+ end
36
+
37
+ private
38
+ def self.detect(date_string)
39
+ error = Pointer.new(:object)
40
+ detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
41
+ matches = detector.matchesInString(date_string, options:0, range:NSMakeRange(0, date_string.length))
42
+ end
43
+ end
44
+
45
+
46
+ class String
47
+ # Use NSDataDetector to parse a string containing a date
48
+ # or duration. These can be of the form:
49
+ #
50
+ # "tomorrow at 7:30 PM"
51
+ # "11.23.2013"
52
+ # "from 7:30 to 10:00 AM"
53
+ #
54
+ # etc.
55
+ def to_date
56
+ DateParser.parse_date(self)
57
+ end
58
+
59
+ def to_timezone
60
+ DateParser.parse_time_zone(self)
61
+ end
62
+
63
+ def to_duration
64
+ DateParser.parse_duration(self)
65
+ end
66
+ end
@@ -148,15 +148,15 @@ module MotionModel
148
148
  alias_method :not_equal, :ne
149
149
 
150
150
  ########### accessor methods #########
151
-
152
- # returns first element that matches.
153
- def first
154
- @collection.first
151
+
152
+ # returns first element or count elements that matches.
153
+ def first(*args)
154
+ to_a.send(:first, *args)
155
155
  end
156
-
157
- # returns last element that matches.
158
- def last
159
- @collection.last
156
+
157
+ # returns last element or count elements that matches.
158
+ def last(*args)
159
+ to_a.send(:last, *args)
160
160
  end
161
161
 
162
162
  # returns all elements that match as an array.
@@ -166,7 +166,7 @@ module MotionModel
166
166
 
167
167
  # returns all elements that match as an array.
168
168
  def to_a
169
- @collection
169
+ @collection || []
170
170
  end
171
171
 
172
172
  # each is a shortcut method to turn a query into an iterator. It allows
@@ -0,0 +1,66 @@
1
+ module DateParser
2
+ # Parse a date string: E.g.:
3
+ #
4
+ # DateParser.parse_date "There is a date in here tomorrow at 9:00 AM"
5
+ #
6
+ # => 2013-02-20 09:00:00 -0800
7
+ def self.parse_date(date_string)
8
+ detect(date_string).first.date
9
+ end
10
+
11
+ # Parse time zone from date
12
+ #
13
+ # ateParser.parse_date "There is a date in here tomorrow at 9:00 AM EDT"
14
+ #
15
+ # Caveat: This is implemented per Apple documentation. I've never really
16
+ # seen it work.
17
+ def self.parse_time_zone(date_string)
18
+ detect(date_string).first.timeZone
19
+ end
20
+
21
+ # Parse a date string: E.g.:
22
+ #
23
+ # SugarCube::DateParser.parse_date "You have a meeting from 9:00 AM to 3:00 PM"
24
+ #
25
+ # => 21600.0
26
+ #
27
+ # Divide by 3600.0 to get number of hours duration.
28
+ def self.parse_duration(date_string)
29
+ detect(date_string).first.send(:duration)
30
+ end
31
+
32
+ # Parse a date into a raw match array for further processing
33
+ def self.match(date_string)
34
+ detect(date_string)
35
+ end
36
+
37
+ private
38
+ def self.detect(date_string)
39
+ error = Pointer.new(:object)
40
+ detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
41
+ matches = detector.matchesInString(date_string, options:0, range:NSMakeRange(0, date_string.length))
42
+ end
43
+ end
44
+
45
+
46
+ class String
47
+ # Use NSDataDetector to parse a string containing a date
48
+ # or duration. These can be of the form:
49
+ #
50
+ # "tomorrow at 7:30 PM"
51
+ # "11.23.2013"
52
+ # "from 7:30 to 10:00 AM"
53
+ #
54
+ # etc.
55
+ def to_date
56
+ DateParser.parse_date(self)
57
+ end
58
+
59
+ def to_timezone
60
+ DateParser.parse_time_zone(self)
61
+ end
62
+
63
+ def to_duration
64
+ DateParser.parse_duration(self)
65
+ end
66
+ end
File without changes
File without changes
File without changes
@@ -1,5 +1,15 @@
1
1
  module MotionModel
2
2
  module Formotion
3
+ def self.included(base)
4
+ base.extend(PublicClassMethods)
5
+ end
6
+ module PublicClassMethods
7
+ def has_formotion_sections(sections = {})
8
+ define_method( "formotion_sections") do
9
+ sections
10
+ end
11
+ end
12
+ end
3
13
  FORMOTION_MAP = {
4
14
  :string => :string,
5
15
  :date => :date,
@@ -53,22 +63,40 @@ module MotionModel
53
63
  # and <tt>updated_at</tt> are suppressed. If you want these shown in
54
64
  # your Formotion form, set <tt>expose_auto_date_fields</tt> to <tt>true</tt>
55
65
  #
56
- # If you want a title for your Formotion form, set the <tt>section_title</tt>
66
+ # If you want a title for your Formotion form, set the <tt>form_title</tt>
57
67
  # argument to a string that will become that title.
58
- def to_formotion(section_title = nil, expose_auto_date_fields = false)
68
+ def to_formotion(form_title = nil, expose_auto_date_fields = false, first_section_title = nil)
59
69
  @expose_auto_date_fields = expose_auto_date_fields
60
- form = {
61
- sections: [{}]
62
- }
63
70
 
64
- section = form[:sections].first
65
- section[:title] ||= section_title
66
- section[:rows] = []
71
+ sections = {
72
+ default: {rows: []}
73
+ }
74
+ if respond_to? 'formotion_sections'
75
+ formotion_sections.each do |k,v|
76
+ sections[k] = v
77
+ sections[k][:rows] = []
78
+ end
79
+ end
80
+ sections[:default][:title] ||= first_section_title
67
81
 
68
82
  returnable_columns.each do |column|
69
83
  value = value_for(column)
70
84
  h = default_hash_for(column, value)
71
- section[:rows].push(combine_options(column, h))
85
+ s = column(column).options[:formotion] ? column(column).options[:formotion][:section] : nil
86
+ if s
87
+ sections[s] ||= {}
88
+ sections[s][:rows].push(combine_options(column,h))
89
+ else
90
+ sections[:default][:rows].push(combine_options(column, h))
91
+ end
92
+ end
93
+
94
+ form = {
95
+ sections: []
96
+ }
97
+ form[:title] ||= form_title
98
+ sections.each do |k,section|
99
+ form[:sections] << section
72
100
  end
73
101
  form
74
102
  end
@@ -226,14 +226,14 @@ module MotionModel
226
226
  # Note collection is not emptied, and next_id is not reset.
227
227
  end
228
228
 
229
- # Retrieves first row of query
230
- def first
231
- all.first
229
+ # Retrieves first row or count rows of query
230
+ def first(*args)
231
+ all.send(:first, *args)
232
232
  end
233
233
 
234
- # Retrieves last row of query
235
- def last
236
- all.last
234
+ # Retrieves last row or count rows of query
235
+ def last(*args)
236
+ all.send(:last, *args)
237
237
  end
238
238
 
239
239
  def each(&block)
@@ -250,9 +250,21 @@ module MotionModel
250
250
 
251
251
  private
252
252
 
253
+ attr_accessor :abstract_class
254
+
255
+ def config
256
+ @config ||= begin
257
+ if !superclass.ancestors.include?(MotionModel::Model) || superclass.abstract_class
258
+ {}
259
+ else
260
+ superclass.send(:config).dup
261
+ end
262
+ end
263
+ end
264
+
253
265
  # Hashes to for quick column lookup
254
266
  def _column_hashes
255
- @_column_hashes ||= {}
267
+ config[:column_hashes] ||= {}
256
268
  end
257
269
 
258
270
  # BUGBUG: This appears not to be executed, therefore @_issue_notifications is always nil to begin with.
@@ -630,13 +642,14 @@ module MotionModel
630
642
  end
631
643
 
632
644
  def set_attr(name, value)
633
- send("#{name}=", value)
645
+ method = "#{name}=".to_sym
646
+ respond_to?(method) ? send(method, value) : _set_attr(name, value)
634
647
  end
635
648
 
636
649
  def _set_attr(name, value)
637
650
  name = name.to_sym
638
651
  old_value = @data[name]
639
- new_value = relation_column?(name) ? value : cast_to_type(name, value)
652
+ new_value = !column(name) || relation_column?(name) ? value : cast_to_type(name, value)
640
653
  if new_value != old_value
641
654
  @data[name] = new_value
642
655
  @dirty = true
@@ -766,7 +779,10 @@ module MotionModel
766
779
  self.class.send(:has_relation?, col)
767
780
  end
768
781
 
769
- def rebuild_relation(column_name, instance_or_collection, options = {}) # nodoc
782
+ def rebuild_relation(col, instance_or_collection, options = {}) # nodoc
783
+ end
784
+
785
+ def unload_relation(col)
770
786
  end
771
787
 
772
788
  def initialize_data_columns(column, value) #nodoc
@@ -21,9 +21,11 @@ module MotionModel
21
21
  def cast_to_date(arg)
22
22
  case arg
23
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:%S'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
24
+ return DateParser::parse_date(arg)
25
+ # return NSDate.dateWithNaturalLanguageString(arg.gsub('-','/'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
26
+ when Time, NSDate
27
+ return arg
28
+ # return NSDate.dateWithNaturalLanguageString(arg.strftime('%Y/%m/%d %H:%M:%S'), locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
27
29
  else
28
30
  return arg
29
31
  end
File without changes
File without changes
@@ -4,5 +4,5 @@
4
4
  # or forward port their code to take advantage
5
5
  # of adapters.
6
6
  module MotionModel
7
- VERSION = "0.4.4"
7
+ VERSION = "0.4.5"
8
8
  end
data/motion_model.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/motion_model/version', __FILE__)
2
+ require File.expand_path('../motion/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Steve Ross"]
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
13
  gem.name = "motion_model"
14
14
  gem.require_paths = ["lib"]
15
- gem.add_dependency 'bubble-wrap', '1.3.0.osx'
15
+ gem.add_dependency 'bubble-wrap', '1.3.0'
16
16
  gem.add_dependency 'motion-support', '>=0.1.0'
17
17
  gem.version = MotionModel::VERSION
18
18
  end
data/spec/finder_spec.rb CHANGED
@@ -55,7 +55,23 @@ describe 'finders' do
55
55
  atask = Task.create(:name => 'find me', :details => "details 1")
56
56
  found_task = Task.where(:details).contain("s 1").first.details.should == 'details 1'
57
57
  end
58
-
58
+
59
+ it 'should returns first 5 results for where call' do
60
+ Task.where(:name).contains('task').first(5).length.should == 5
61
+ end
62
+
63
+ it 'should returns last 5 results for where call' do
64
+ Task.where(:name).contains('task').last(5).length.should == 5
65
+ end
66
+
67
+ it 'should returns first element for where call' do
68
+ Task.where(:name).contains('task').first.should.is_a Task
69
+ end
70
+
71
+ it 'should returns last element for where call' do
72
+ Task.where(:name).contains('task').last.should.is_a Task
73
+ end
74
+
59
75
  it "performs set inclusion(in) queries" do
60
76
  class InTest
61
77
  include MotionModel::Model
@@ -70,7 +86,7 @@ describe 'finders' do
70
86
  results = InTest.find(:id).in([3, 5, 7])
71
87
  results.length.should == 3
72
88
  end
73
-
89
+
74
90
  it 'handles case-sensitive queries' do
75
91
  task = Task.create :name => 'Bob'
76
92
  Task.find(:name).eq('bob', :case_sensitive => true).all.length.should == 0
@@ -88,6 +104,29 @@ describe 'finders' do
88
104
  task_id = task.id
89
105
  end
90
106
  end
107
+
108
+ it 'should returns first 5 members of the collection as an array' do
109
+ Task.first(5).length.should.equal(5)
110
+ end
111
+
112
+ it 'should returns last 5 members of the collection as an array' do
113
+ Task.last(5).length.should.equal(5)
114
+ end
115
+
116
+ it 'should be a difference between first and last element' do
117
+ first_records = Task.first(5)
118
+ last_records = Task.last(5)
119
+
120
+ first_records[0].should.not == last_records[0]
121
+ end
122
+
123
+ it 'should returns first element' do
124
+ Task.first.should.is_a Task
125
+ end
126
+
127
+ it 'should returns last element' do
128
+ Task.last.should.is_a Task
129
+ end
91
130
 
92
131
  describe 'block-style finders' do
93
132
  before do
@@ -6,11 +6,14 @@ class ModelWithOptions
6
6
 
7
7
  columns :name => :string,
8
8
  :date => {:type => :date, :formotion => {:picker_type => :date_time}},
9
- :location => :string,
9
+ :location => {:type => :string, :formotion => {:section => :address}},
10
10
  :created_at => :date,
11
11
  :updated_at => :date
12
12
 
13
13
  has_many :related_models
14
+
15
+ has_formotion_sections :address => { title: "Address" }
16
+
14
17
  end
15
18
 
16
19
  class RelatedModel
@@ -42,12 +45,32 @@ describe "formotion" do
42
45
  @subject.to_formotion.should.not.be.nil
43
46
  end
44
47
 
45
- it "has the correct section title" do
46
- @subject.to_formotion('test section')[:sections].first[:title].should == 'test section'
48
+ it "has the correct form title" do
49
+ @subject.to_formotion('test form')[:title].should == 'test form'
50
+ end
51
+
52
+ it "has two sections" do
53
+ @subject.to_formotion[:sections].length.should == 2
54
+ end
55
+
56
+ it "has 2 rows in default section" do
57
+ @subject.to_formotion[:sections].first[:rows].length.should == 2
58
+ end
59
+
60
+ it "does not include title in the default section" do
61
+ @subject.to_formotion[:sections].first[:title].should == nil
62
+ end
63
+
64
+ it "does include title in the :address section" do
65
+ @subject.to_formotion[:sections][1][:title].should == 'Address'
66
+ end
67
+
68
+ it "has 1 row in :address section" do
69
+ @subject.to_formotion[:sections][1][:rows].length.should == 1
47
70
  end
48
71
 
49
- it "has 3 rows" do
50
- @subject.to_formotion('test section')[:sections].first[:rows].length.should == 3
72
+ it "value of location row in :address section is 'my house'" do
73
+ @subject.to_formotion[:sections][1][:rows].first[:value].should == 'my house'
51
74
  end
52
75
 
53
76
  it "value of name row is 'get together'" do
@@ -57,7 +80,7 @@ describe "formotion" do
57
80
  it "binds data from rendered form into model fields" do
58
81
  @subject.from_formotion!({:name => '007 Reunion', :date => 1358197323, :location => "Q's Lab"})
59
82
  @subject.name.should == '007 Reunion'
60
- @subject.date.strftime("%Y-%m-%d %H:%M").should == '2013-01-14 13:02'
83
+ @subject.date.utc.strftime("%Y-%m-%d %H:%M").should == '2013-01-14 21:02'
61
84
  @subject.location.should == "Q's Lab"
62
85
  end
63
86
 
@@ -0,0 +1,35 @@
1
+ describe "cloning configuration data for KVO" do
2
+ class KVOObservable
3
+ include MotionModel::Model
4
+ include MotionModel::ArrayModelAdapter
5
+
6
+ columns :name, :nickname
7
+ end
8
+
9
+ class KVOWatcher
10
+ attr_reader :o
11
+
12
+ include BW::KVO
13
+
14
+ def initialize(o)
15
+ @o = o
16
+ observe(o, :name) do |old_value, new_value|
17
+ end
18
+ end
19
+ end
20
+
21
+ before do
22
+ @observable = KVOObservable.create!(name: 'Jim', nickname: 'Jimmy')
23
+ @watcher = KVOWatcher.new(@observable)
24
+ end
25
+
26
+ it "is a KVO anonymous class" do
27
+ @watcher.o.class.to_s.should.match(/^NSKVO/)
28
+ @watcher.o.class.should.not == KVOObservable
29
+ end
30
+
31
+ it "retrieves attribute values correctly" do
32
+ @watcher.o.name.should == @observable.name
33
+ @watcher.o.nickname.should == @observable.nickname
34
+ end
35
+ 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.4.4
4
+ version: 0.4.5
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: 2013-05-10 00:00:00.000000000 Z
12
+ date: 2013-06-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bubble-wrap
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.3.0.osx
21
+ version: 1.3.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 1.3.0.osx
29
+ version: 1.3.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: motion-support
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -59,18 +59,20 @@ files:
59
59
  - Rakefile
60
60
  - app/app_delegate.rb
61
61
  - lib/motion_model.rb
62
- - lib/motion_model/adapters/array_model_adapter.rb
63
- - lib/motion_model/adapters/array_model_persistence.rb
64
- - lib/motion_model/ext.rb
65
- - lib/motion_model/input_helpers.rb
66
- - lib/motion_model/model/array_finder_query.rb
67
- - lib/motion_model/model/column.rb
68
- - lib/motion_model/model/formotion.rb
69
- - lib/motion_model/model/model.rb
70
- - lib/motion_model/model/model_casts.rb
71
- - lib/motion_model/model/transaction.rb
72
- - lib/motion_model/validatable.rb
73
- - lib/motion_model/version.rb
62
+ - lib/motion_model/date_parser.rb
63
+ - motion/adapters/array_finder_query.rb
64
+ - motion/adapters/array_model_adapter.rb
65
+ - motion/adapters/array_model_persistence.rb
66
+ - motion/date_parser.rb
67
+ - motion/ext.rb
68
+ - motion/input_helpers.rb
69
+ - motion/model/column.rb
70
+ - motion/model/formotion.rb
71
+ - motion/model/model.rb
72
+ - motion/model/model_casts.rb
73
+ - motion/model/transaction.rb
74
+ - motion/validatable.rb
75
+ - motion/version.rb
74
76
  - motion_model.gemspec
75
77
  - spec/adapter_spec.rb
76
78
  - spec/array_model_persistence_spec.rb
@@ -80,6 +82,7 @@ files:
80
82
  - spec/ext_spec.rb
81
83
  - spec/finder_spec.rb
82
84
  - spec/formotion_spec.rb
85
+ - spec/kvo_config_clone_spec.rb
83
86
  - spec/model_casting_spec.rb
84
87
  - spec/model_hook_spec.rb
85
88
  - spec/model_spec.rb
@@ -120,6 +123,7 @@ test_files:
120
123
  - spec/ext_spec.rb
121
124
  - spec/finder_spec.rb
122
125
  - spec/formotion_spec.rb
126
+ - spec/kvo_config_clone_spec.rb
123
127
  - spec/model_casting_spec.rb
124
128
  - spec/model_hook_spec.rb
125
129
  - spec/model_spec.rb