motion-prime 0.4.5 → 0.5.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 (88) hide show
  1. checksums.yaml +14 -6
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +10 -8
  6. data/ROADMAP.md +9 -10
  7. data/Rakefile +1 -1
  8. data/doc/code/getting_started.rb +3 -3
  9. data/doc/code/screens.rb +25 -10
  10. data/doc/code/sections.rb +41 -0
  11. data/doc/docs/getting_started.html +8 -3
  12. data/doc/docs/screens.html +58 -19
  13. data/doc/docs/sections.html +134 -0
  14. data/files/Gemfile +7 -1
  15. data/files/Gemfile.lock +18 -9
  16. data/files/Rakefile +2 -11
  17. data/files/app/app_delegate.rb +2 -2
  18. data/files/app/config/base.rb +0 -4
  19. data/files/app/screens/application_screen.rb +2 -2
  20. data/files/app/screens/home_screen.rb +2 -0
  21. data/files/app/screens/sidebar_screen.rb +3 -3
  22. data/files/app/sections/home/section.rb +3 -0
  23. data/files/app/sections/sidebar/action.rb +1 -1
  24. data/files/app/styles/home.rb +9 -0
  25. data/files/app/styles/sidebar.rb +3 -3
  26. data/lib/motion-prime.rb +9 -0
  27. data/motion-prime/api_client.rb +5 -1
  28. data/motion-prime/app_delegate.rb +40 -45
  29. data/motion-prime/core_ext/kernel.rb +8 -0
  30. data/motion-prime/elements/_content_text_mixin.rb +3 -1
  31. data/motion-prime/elements/_text_mixin.rb +1 -1
  32. data/motion-prime/elements/base_element.rb +6 -5
  33. data/motion-prime/elements/draw/image.rb +6 -1
  34. data/motion-prime/elements/view_with_section.rb +7 -0
  35. data/motion-prime/helpers/has_style_chain_builder.rb +4 -1
  36. data/motion-prime/models/_association_mixin.rb +139 -0
  37. data/motion-prime/models/_base_mixin.rb +184 -0
  38. data/motion-prime/models/_dirty_mixin.rb +31 -0
  39. data/motion-prime/models/_finder_mixin.rb +208 -0
  40. data/motion-prime/models/{bag.rb → _nano_bag_mixin.rb} +4 -4
  41. data/motion-prime/models/{sync.rb → _sync_mixin.rb} +75 -76
  42. data/motion-prime/models/json.rb +6 -9
  43. data/motion-prime/models/model.rb +24 -172
  44. data/motion-prime/{mp.rb → prime.rb} +0 -1
  45. data/motion-prime/screens/_base_mixin.rb +9 -10
  46. data/motion-prime/screens/_navigation_mixin.rb +12 -17
  47. data/motion-prime/screens/extensions/_indicators_mixin.rb +1 -1
  48. data/motion-prime/screens/extensions/_navigation_bar_mixin.rb +3 -3
  49. data/motion-prime/screens/{base_screen.rb → screen.rb} +11 -5
  50. data/motion-prime/sections/_cell_section_mixin.rb +13 -0
  51. data/motion-prime/sections/_draw_section_mixin.rb +17 -0
  52. data/motion-prime/sections/base_section.rb +51 -16
  53. data/motion-prime/sections/form/base_field_section.rb +27 -16
  54. data/motion-prime/sections/form/base_header_section.rb +4 -3
  55. data/motion-prime/sections/form/password_field_section.rb +4 -0
  56. data/motion-prime/sections/form/select_field_section.rb +4 -0
  57. data/motion-prime/sections/form/string_field_section.rb +4 -0
  58. data/motion-prime/sections/form/submit_field_section.rb +4 -0
  59. data/motion-prime/sections/form/text_field_section.rb +4 -0
  60. data/motion-prime/sections/form.rb +7 -1
  61. data/motion-prime/sections/tabbed.rb +1 -1
  62. data/motion-prime/sections/table/table_delegate.rb +5 -0
  63. data/motion-prime/sections/table.rb +71 -51
  64. data/motion-prime/services/logger.rb +37 -0
  65. data/motion-prime/support/mp_cell_with_section.rb +9 -4
  66. data/motion-prime/support/tab_bar_controller.rb +2 -1
  67. data/motion-prime/version.rb +1 -1
  68. data/motion-prime/views/layout.rb +1 -1
  69. data/motion-prime/views/view_builder.rb +7 -0
  70. data/motion-prime.gemspec +1 -1
  71. data/spec/delegate/{base_delegate_spec.rb → delegate_spec.rb} +1 -1
  72. data/spec/helpers/{base_delegate.rb → delegates.rb} +0 -0
  73. data/spec/helpers/models.rb +11 -18
  74. data/spec/helpers/{base_screen.rb → screens.rb} +1 -1
  75. data/spec/models/{association_spec.rb → associations_spec.rb} +1 -1
  76. data/spec/models/bag_spec.rb +1 -1
  77. data/spec/models/errors_spec.rb +1 -1
  78. data/spec/models/finder_spec.rb +1 -1
  79. data/spec/models/json.rb +87 -0
  80. data/spec/models/model_spec.rb +23 -3
  81. data/spec/models/store_extension_spec.rb +1 -1
  82. data/spec/models/store_spec.rb +1 -1
  83. data/spec/screens/{base_screen_spec.rb → screen_spec.rb} +5 -1
  84. metadata +52 -43
  85. data/motion-prime/models/association.rb +0 -134
  86. data/motion-prime/models/base.rb +0 -27
  87. data/motion-prime/models/finder.rb +0 -202
  88. data/motion-prime/screens/sidebar_container_screen.rb +0 -80
@@ -0,0 +1,139 @@
1
+ module MotionPrime
2
+ module ModelAssociationMixin
3
+ extend ::MotionSupport::Concern
4
+
5
+ def _bags
6
+ @_bags ||= {}
7
+ end
8
+
9
+ def save
10
+ _bags.values.each do |bag|
11
+ bag.store = self.store
12
+ bag.save
13
+ end
14
+ super
15
+ end
16
+
17
+ module ClassMethods
18
+ # Defines bag associated with model, creates accessor for bag
19
+ #
20
+ # @param [String] name - the name of bag
21
+ # @return [Nil]
22
+ def bag(name)
23
+ define_method(name) do |*args, &block|
24
+ return _bags[name] if _bags[name]
25
+ bag_key = self.info[name]
26
+ if bag_key.present?
27
+ bag = self.class.store.bagsWithKeysInArray([bag_key]).first
28
+ end
29
+ unless bag
30
+ bag = Bag.bag
31
+ self.info[name] = bag.key
32
+ end
33
+
34
+ _bags[name] = bag
35
+ end
36
+
37
+ define_method((name + "=").to_sym) do |*args, &block|
38
+ bag = self.send(name)
39
+ case args[0]
40
+ when Bag
41
+ bag.clear
42
+ bag += args[0].saved.values
43
+ when Array
44
+ bag.clear
45
+ bag += args[0]
46
+ else
47
+ raise StoreError, "Unexpected type assigned to bags, must be an Array or MotionPrime::Bag, now: #{args[0].class}"
48
+ end
49
+ bag
50
+ end
51
+ end
52
+
53
+ # Defines has one association for model, creates accessor for association
54
+ #
55
+ # @param [String] name - the name of association
56
+ # @return [Nil]
57
+ def has_one(association_name, options = {})
58
+ bag_name = "#{association_name.pluralize}_bag"
59
+ self.bag bag_name.to_sym
60
+
61
+ self._associations ||= {}
62
+ self._associations[association_name] = options.merge(type: :one)
63
+
64
+ define_method("#{association_name}=") do |value|
65
+ self.send(bag_name).clear
66
+ self.send(:"#{bag_name}") << value
67
+ value
68
+ end
69
+ define_method("#{association_name}_attributes=") do |value|
70
+ self.send(bag_name).clear
71
+
72
+ association = association_name.classify.constantize.new
73
+ association.fetch_with_attributes(value)
74
+ association.save
75
+ self.send(:"#{bag_name}") << association
76
+ self.send(:"#{bag_name}").save
77
+ association
78
+ end
79
+ define_method("#{association_name}") do
80
+ self.send(:"#{bag_name}").to_a.first
81
+ end
82
+ end
83
+
84
+ # Defines has many association for model, creates accessor for association
85
+ #
86
+ # @param [String] name - the name of association
87
+ # @return [Nil]
88
+ def has_many(association_name, options = {})
89
+ bag_name = "#{association_name}_bag"
90
+ self.bag bag_name.to_sym
91
+
92
+ self._associations ||= {}
93
+ self._associations[association_name] = options.merge(type: :many)
94
+
95
+ define_method("#{association_name}_attributes=") do |value|
96
+ self.send(bag_name).clear
97
+
98
+ pending_save_counter = 0
99
+ collection = value.inject({}) do |result, attrs|
100
+ model = association_name.classify.constantize.new
101
+ model.fetch_with_attributes(attrs)
102
+ unique_key = model.id || "pending_#{pending_save_counter+=1}"
103
+ result.merge(unique_key => model)
104
+ end
105
+ association_data = collection.values
106
+ self.send(:"#{bag_name}=", association_data)
107
+ self.send(:"#{bag_name}").save
108
+ association_data
109
+ end
110
+ define_method("#{association_name}=") do |value|
111
+ self.send(bag_name).clear
112
+ self.send(:"#{bag_name}=", value)
113
+ end
114
+ define_method("#{association_name}") do |*args|
115
+ bag = self.send(:"#{bag_name}")
116
+ collection_options = {
117
+ association_name: association_name,
118
+ inverse_relation: {
119
+ type: :has_one,
120
+ name: self.class_name_without_kvo.demodulize.underscore,
121
+ instance: self
122
+ }
123
+ }
124
+ AssociationCollection.new(bag, collection_options, *args)
125
+ end
126
+ end
127
+
128
+ def belongs_to(association_name, options = {})
129
+ self._associations ||= {}
130
+ self._associations[association_name] = {
131
+ type: :belongs_to_one,
132
+ class_name: association_name.classify
133
+ }.merge(options)
134
+
135
+ self.send(:attr_accessor, association_name)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,184 @@
1
+ module MotionPrime
2
+ module ModelBaseMixin
3
+ extend ::MotionSupport::Concern
4
+
5
+ def self.included(base)
6
+ base.class_attribute :default_sort_options
7
+ end
8
+
9
+ def save
10
+ raise StoreError, 'No store provided' unless self.store
11
+ error_ptr = Pointer.new(:id)
12
+ self.store.addObject(self, error: error_ptr)
13
+ raise StoreError, error_ptr[0].description if error_ptr[0]
14
+ self
15
+ end
16
+
17
+ def delete
18
+ raise StoreError, 'No store provided' unless self.store
19
+
20
+ error_ptr = Pointer.new(:id)
21
+ self.store.removeObject(self, error: error_ptr)
22
+ raise StoreError, error_ptr[0].description if error_ptr[0]
23
+ self
24
+ end
25
+
26
+ def store
27
+ super || self.class.store
28
+ end
29
+
30
+ def assign_attributes(new_attributes, options = {})
31
+ attributes = new_attributes.symbolize_keys
32
+ attributes.each do |k, v|
33
+ if has_attribute?(k)
34
+ assign_attribute(k, v) unless options[:skip_nil_values] && v.nil?
35
+ elsif options[:validate_attribute_presence]
36
+ raise(StoreError, "unknown attribute: '#{k}'")
37
+ else
38
+ NSLog("unknown attribute: #{k}")
39
+ end
40
+ end
41
+ end
42
+
43
+ def assign_attribute(name, value)
44
+ self.send("#{name}=", value) if has_attribute?(name)
45
+ end
46
+
47
+ def has_attribute?(name)
48
+ respond_to?("#{name}=")
49
+ end
50
+
51
+ def attributes_hash
52
+ self.info.to_hash.symbolize_keys
53
+ end
54
+
55
+ def new_record?
56
+ id.blank?
57
+ end
58
+
59
+ def persisted?
60
+ !new_record?
61
+ end
62
+
63
+ def model_name
64
+ self.class_name_without_kvo.underscore
65
+ end
66
+
67
+ def inspect
68
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}> " + MotionPrime::JSON.generate(info)
69
+ end
70
+
71
+ module ClassMethods
72
+ # Initialize a new object
73
+ #
74
+ # Examples:
75
+ # User.new(name: "Bob", age: 10)
76
+ #
77
+ # @return MotionPrime::Model unsaved model
78
+ def new(data = {}, options = {})
79
+ data.keys.each do |key|
80
+ unless self.attributes.member? key.to_sym
81
+ if options[:validate_attribute_presence]
82
+ raise StoreError, "unknown attribute: '#{key}'"
83
+ else
84
+ data.delete(key)
85
+ end
86
+ end
87
+ end
88
+
89
+ object = self.nanoObjectWithDictionary(data)
90
+ object
91
+ end
92
+
93
+ # Initialize a new object and save it
94
+ #
95
+ # Examples:
96
+ # User.create(name: "Bob", age: 10)
97
+ #
98
+ # @return MotionPrime::Model saved model
99
+ def create(data = {})
100
+ object = self.new(data)
101
+ object.save
102
+ end
103
+
104
+ # Define model attribute
105
+ #
106
+ # Examples:
107
+ # class User < MotionPrime::Model
108
+ # attribute :name
109
+ # attribute :age
110
+ # end
111
+ #
112
+ # @return Nil
113
+ def attribute(name, options = {})
114
+ attributes << name
115
+
116
+ define_method(name) do |*args, &block|
117
+ self.info[name]
118
+ end
119
+
120
+ define_method((name + "=").to_sym) do |*args, &block|
121
+ value = args[0]
122
+ case options[:type].to_s
123
+ when 'integer' then value = value.to_i
124
+ when 'float' then value = value.to_f
125
+ end unless value.nil?
126
+
127
+ self.info[name] = value
128
+ end
129
+
130
+ if options[:type].to_s == 'boolean'
131
+ define_method("#{name}?") do
132
+ !!self.info[name]
133
+ end
134
+ end
135
+ end
136
+
137
+ # Set or return all model attribute names
138
+ #
139
+ # @return Array array of attribute names
140
+ def attributes(*attrs)
141
+ if attrs.size > 0
142
+ attrs.each{|attr| attribute attr}
143
+ else
144
+ @attributes ||= []
145
+ end
146
+ end
147
+
148
+ # Return store associated with model class, or shared store by default
149
+ #
150
+ # @return MotionPrime::Store store
151
+ def store
152
+ @store ||= MotionPrime::Store.shared_store
153
+ end
154
+
155
+ # Define store associated with model class
156
+ #
157
+ # @param MotionPrime::Store store
158
+ # @return MotionPrime::Store store
159
+ def store=(store)
160
+ @store = store
161
+ end
162
+
163
+ # Count of models
164
+ #
165
+ # @return Fixnum count
166
+ def count
167
+ self.store.count(self)
168
+ end
169
+
170
+ # Delete objects from store
171
+ #
172
+ # @param [Array, MotionPrime::Model] objects to delete
173
+ # @return [Array] result
174
+ def delete(*args)
175
+ keys = find_keys(*args)
176
+ self.store.delete_keys(keys)
177
+ end
178
+
179
+ def default_sort(sort_options)
180
+ self.default_sort_options = sort_options
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,31 @@
1
+ module MotionPrime
2
+ module ModelDirtyMixin
3
+ extend ::MotionSupport::Concern
4
+
5
+ def self.included(base)
6
+ base.class_attribute :_changed_attributes
7
+ end
8
+
9
+ def track_changed_attributes(&block)
10
+ @_changed_attributes ||= {}
11
+ old_attrs = self.info.clone
12
+ result = block.call
13
+ new_attrs = self.info.clone
14
+ new_attrs.each do |key, value|
15
+ if value != old_attrs[key] && ! @_changed_attributes.has_key?(key.to_s)
16
+ @_changed_attributes[key.to_s] = old_attrs[key]
17
+ end
18
+ end
19
+ result
20
+ end
21
+
22
+ def has_changed?(key = nil)
23
+ @_changed_attributes ||= {}
24
+ if key
25
+ @_changed_attributes.has_key?(key.to_s)
26
+ else
27
+ @_changed_attributes.present?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,208 @@
1
+ module MotionPrime
2
+ module ModelFinderMixin
3
+ extend ::MotionSupport::Concern
4
+
5
+ module ClassMethods
6
+ attr_accessor :bare_class
7
+
8
+ # Find all models
9
+ #
10
+ # @return [Array] array of models
11
+ def all(*args)
12
+ return [] unless self.store
13
+
14
+ if args[0].is_a?(Hash)
15
+ sort_options = args[0][:sort] || {}
16
+ else
17
+ sort_options = {}
18
+ end
19
+
20
+ if sort_options.empty?
21
+ self.store.objectsOfClassNamed(self.bare_class_name)
22
+ else
23
+ sort_descriptors = sort_descriptor_with_options(sort_options)
24
+ self.store.objectsOfClassNamed(self.bare_class_name, usingSortDescriptors:sort_descriptors)
25
+ end
26
+ end
27
+
28
+ # Find last model model by default order
29
+ def last
30
+ all.last
31
+ end
32
+
33
+ # Find first model model by default order
34
+ def first
35
+ all.first
36
+ end
37
+
38
+ # Find model by criteria
39
+ #
40
+ # Examples:
41
+ # User.find(:name, NSFEqualTo, "Bob") # => [<User#1>]
42
+ # User.find(:name => "Bob") # => [<User#1>]
43
+ # User.find(:name => {NSFEqualTo => "Bob"}) # => [<User#1>]
44
+ #
45
+ # @return [Array] array of models
46
+ def find(*arg)
47
+ if arg[0].is_a?(Hash)
48
+ # hash style
49
+ options = arg[0]
50
+ if arg[1] && arg[1].is_a?(Hash)
51
+ sort_options = arg[1][:sort] || {}
52
+ else
53
+ sort_options = {}
54
+ end
55
+ elsif arg[0] && arg[1] && arg[2]
56
+ # standard way to find
57
+ options = {arg[0] => {arg[1] => arg[2]}}
58
+ if arg[4] && arg[4].is_a?(Hash)
59
+ sort_options = arg[4][:sort] || {}
60
+ else
61
+ sort_options = {}
62
+ end
63
+ elsif arg.empty?
64
+ options = {}
65
+ sort_options = {}
66
+ else
67
+ raise "unexpected parameters #{arg}"
68
+ end
69
+ search = NSFNanoSearch.searchWithStore(self.store)
70
+
71
+ expressions = expressions_with_options(options)
72
+ search.expressions = expressions
73
+
74
+ sort_descriptors = sort_descriptor_with_options(sort_options)
75
+ search.sort = sort_descriptors
76
+ search.filterClass = self.bare_class_name
77
+
78
+ error_ptr = Pointer.new(:id)
79
+ searchResults = search.searchObjectsWithReturnType(NSFReturnObjects, error:error_ptr)
80
+ raise StoreError, error_ptr[0].description if error_ptr[0]
81
+
82
+ if searchResults.is_a?(NSDictionary)
83
+ searchResults.values
84
+ else
85
+ searchResults
86
+ end
87
+ end
88
+
89
+ # Find model keys by criteria
90
+ #
91
+ # Examples:
92
+ # User.find_keys(:name, NSFEqualTo, "Bob") # => ["1"]
93
+ # User.find_keys(:name => "Bob") # => ["1"]
94
+ # User.find_keys(:name => {NSFEqualTo => "Bob"}) # => ["1"]
95
+ #
96
+ # @return [Array] array of models
97
+ def find_keys(*arg)
98
+ if arg[0].is_a?(Hash)
99
+ # hash style
100
+ options = arg[0]
101
+ if arg[1] && arg[1].is_a?(Hash)
102
+ sort_options = arg[1][:sort] || {}
103
+ else
104
+ sort_options = {}
105
+ end
106
+ elsif arg[0] && arg[1] && arg[2]
107
+ # standard way to find
108
+ options = {arg[0] => {arg[1] => arg[2]}}
109
+ if arg[4] && arg[4].is_a?(Hash)
110
+ sort_options = arg[4][:sort] || {}
111
+ else
112
+ sort_options = {}
113
+ end
114
+ elsif arg.empty?
115
+ options = {}
116
+ sort_options = {}
117
+ else
118
+ raise "unexpected parameters #{arg}"
119
+ end
120
+
121
+ search = NSFNanoSearch.searchWithStore(self.store)
122
+
123
+ expressions = expressions_with_options(options)
124
+ search.expressions = expressions
125
+
126
+ sort_descriptors = sort_descriptor_with_options(sort_options)
127
+ search.sort = sort_descriptors
128
+ search.filterClass = self.bare_class_name
129
+
130
+ error_ptr = Pointer.new(:id)
131
+ searchResults = search.searchObjectsWithReturnType(NSFReturnKeys, error:error_ptr)
132
+ raise StoreError, error_ptr[0].description if error_ptr[0]
133
+
134
+ if searchResults.is_a?(NSDictionary)
135
+ searchResults.values
136
+ else
137
+ searchResults
138
+ end
139
+ end
140
+
141
+ # Find a model by key
142
+ #
143
+ # Examples:
144
+ # User.find_by_key(my_key)
145
+ #
146
+ # @return [Object, Nil] an object or nil (if not found)
147
+ def find_by_key(key)
148
+ search = NSFNanoSearch.searchWithStore(self.store)
149
+ search.key = key
150
+
151
+ error_ptr = Pointer.new(:id)
152
+ searchResult = search.searchObjectsWithReturnType(NSFReturnObjects, error:error_ptr).first
153
+ raise StoreError, error_ptr[0].description if error_ptr[0]
154
+
155
+ searchResult.last if searchResult
156
+ end
157
+
158
+ def bare_class_name
159
+ subject = @bare_class || self
160
+ subject.to_s.split("::").last
161
+ end
162
+
163
+ private
164
+ def expressions_with_options(options)
165
+ expressions = []
166
+
167
+ options.each do |key, val|
168
+ attribute = NSFNanoPredicate.predicateWithColumn(NSFAttributeColumn, matching:NSFEqualTo, value:key.to_s)
169
+ expression = NSFNanoExpression.expressionWithPredicate(attribute)
170
+ if val.is_a?(Hash)
171
+ val.each do |operator, sub_val|
172
+ value = NSFNanoPredicate.predicateWithColumn(NSFValueColumn, matching:operator, value:sub_val.to_s)
173
+ expression.addPredicate(value, withOperator:NSFAnd)
174
+ end
175
+ elsif val.is_a?(Array)
176
+ value = NSFNanoPredicate.predicateWithColumn(NSFValueColumn, matching:NSFEqualTo, value:val.pop)
177
+ expression.addPredicate(value, withOperator:NSFAnd)
178
+
179
+ val.each do |sub_val|
180
+ value = NSFNanoPredicate.predicateWithColumn(NSFValueColumn, matching:NSFEqualTo, value:sub_val.to_s)
181
+ expression.addPredicate(value, withOperator:NSFOr)
182
+ end
183
+ else
184
+ value = NSFNanoPredicate.predicateWithColumn(NSFValueColumn, matching:NSFEqualTo, value:val.to_s)
185
+ expression.addPredicate(value, withOperator:NSFAnd)
186
+ end
187
+ expressions << expression
188
+ end
189
+ return expressions
190
+ end
191
+
192
+ SORT_MAPPING = {
193
+ 'asc' => true,
194
+ 'desc' => false,
195
+ }
196
+
197
+ def sort_descriptor_with_options(options)
198
+ sorter = options.collect do |opt_key, opt_val|
199
+ if SORT_MAPPING.keys.include?(opt_val.to_s.downcase)
200
+ NSFNanoSortDescriptor.alloc.initWithAttribute(opt_key.to_s, ascending:SORT_MAPPING[opt_val.to_s.downcase])
201
+ else
202
+ raise "unsupported sort parameters: #{opt_val}"
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -1,6 +1,6 @@
1
- motion_require './finder.rb'
1
+ motion_require './_finder_mixin.rb'
2
2
  module MotionPrime
3
- module BagInstanceMethods
3
+ module NanoBagMixin
4
4
  def self.included(base)
5
5
  base.class_eval do
6
6
  alias_method :saved, :savedObjects
@@ -131,6 +131,6 @@ module MotionPrime
131
131
  end
132
132
 
133
133
  class NSFNanoBag
134
- include MotionPrime::ModelFinderMethods
135
- include MotionPrime::BagInstanceMethods
134
+ include MotionPrime::ModelFinderMixin::ClassMethods
135
+ include MotionPrime::NanoBagMixin
136
136
  end