motion-prime 0.1.7 → 0.2.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.
- checksums.yaml +8 -8
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/files/app/config/base.rb +7 -4
- data/files/app/styles/sidebar.rb +4 -4
- data/lib/motion-prime.rb +1 -0
- data/motion-prime/config/base.rb +5 -0
- data/motion-prime/elements/_text_height_mixin.rb +4 -4
- data/motion-prime/elements/base.rb +11 -5
- data/motion-prime/elements/draw.rb +105 -26
- data/motion-prime/elements/draw/image.rb +2 -2
- data/motion-prime/elements/draw/label.rb +20 -3
- data/motion-prime/elements/error_message.rb +23 -0
- data/motion-prime/elements/label.rb +8 -0
- data/motion-prime/models/association.rb +0 -1
- data/motion-prime/models/base.rb +8 -192
- data/motion-prime/models/errors.rb +62 -1
- data/motion-prime/models/exceptions.rb +3 -0
- data/motion-prime/models/model.rb +33 -1
- data/motion-prime/models/sync.rb +233 -0
- data/motion-prime/screens/_base_mixin.rb +4 -1
- data/motion-prime/screens/_navigation_mixin.rb +5 -5
- data/motion-prime/sections/base.rb +18 -5
- data/motion-prime/sections/form.rb +75 -16
- data/motion-prime/sections/form/base_field_section.rb +52 -1
- data/motion-prime/sections/form/select_field_section.rb +14 -1
- data/motion-prime/sections/form/string_field_section.rb +20 -5
- data/motion-prime/sections/form/switch_field_section.rb +33 -0
- data/motion-prime/sections/form/table_field_section.rb +40 -0
- data/motion-prime/sections/form/text_field_section.rb +23 -6
- data/motion-prime/sections/table.rb +25 -8
- data/motion-prime/styles/base.rb +31 -4
- data/motion-prime/support/dm_button.rb +3 -2
- data/motion-prime/version.rb +1 -1
- data/motion-prime/views/layout.rb +1 -1
- data/motion-prime/views/view_builder.rb +82 -66
- data/motion-prime/views/view_styler.rb +2 -0
- data/resources/fonts/ubuntu.ttf +0 -0
- data/spec/helpers/models.rb +1 -1
- data/spec/models/association_spec.rb +1 -1
- data/spec/models/errors_spec.rb +29 -0
- data/spec/models/finder_spec.rb +1 -1
- data/spec/models/{base_model_spec.rb → model_spec.rb} +30 -1
- data/spec/models/store_extension_spec.rb +1 -1
- data/spec/models/store_spec.rb +1 -1
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTdmYjFmM2NhYWE3ZGQyNzFjYWZjYjg2NzUzOTFkMTkwZmVjYTBjMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NmI1OTFjNGRmYmZjOTYyNWExOGJlMjQ4YjVjYzc4M2M0Y2M3ZWQ4Zg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODdiZTc3ZmIyM2ZlZDJhOTg1YTU2OGEyODFhZWE5MGI2NWUzY2ZiYTQ5NzU5
|
10
|
+
ZGFlYmRkZDllYjY4MjA4YjA3YTE5YmZlNmE4NjU5Zjk3OTVhNTJkM2IwMDI4
|
11
|
+
NGIzYTRjYzg5MzBhMmM1NjY0NmJmY2U4MWMzN2JiODczZWNmMjY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MjBiMDY2NTg1ZWM1OGU3ZDUzYTcyYmY5YTgyMWVlNmE2M2EzYTE0YjVmYjBk
|
14
|
+
YzExOTI5ZDQ3MDZlN2Q1MDkwNjE0ZTU0OTRlM2Q1NjA2Y2ZmNThmZmUxNzUy
|
15
|
+
OThlMzU4NTI5ZDJkOTIwMmE3MDA2OTZkM2I2OTAwZDViY2ZmMzU=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== 0.2.0
|
2
|
+
* MP::BaseModel improvements
|
3
|
+
* Added ability to observe form field errors
|
4
|
+
* Use MP::Config for style configurations
|
5
|
+
|
1
6
|
=== 0.1.7
|
2
7
|
* MP::BaseModel#fetch_associations now supports callback option
|
3
8
|
* MP::LabelDrawElement now supports `size_to_fit` option
|
data/Gemfile.lock
CHANGED
data/files/app/config/base.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
MP = MotionPrime unless defined?(MP)
|
2
|
+
|
3
|
+
MP::Config.color do |color|
|
4
|
+
color.base = 0x3aa9b6
|
5
|
+
color.dark = 0x41929c
|
6
|
+
end
|
4
7
|
|
5
8
|
# setup model's store
|
6
|
-
|
9
|
+
MP::Store.connect
|
data/files/app/styles/sidebar.rb
CHANGED
@@ -2,7 +2,7 @@ MotionPrime::Styles.define :sidebar do
|
|
2
2
|
# navigation layout
|
3
3
|
# ----------
|
4
4
|
style :screen,
|
5
|
-
background_color:
|
5
|
+
background_color: MP::Config.color.base,
|
6
6
|
opaque: true
|
7
7
|
|
8
8
|
style :table,
|
@@ -10,8 +10,8 @@ MotionPrime::Styles.define :sidebar do
|
|
10
10
|
left: 0,
|
11
11
|
width: 320,
|
12
12
|
bottom: 0,
|
13
|
-
background_color:
|
14
|
-
separator_color:
|
13
|
+
background_color: MP::Config.color.base,
|
14
|
+
separator_color: MP::Config.color.dark,
|
15
15
|
opaque: true
|
16
16
|
|
17
17
|
style :table_cell,
|
@@ -19,7 +19,7 @@ MotionPrime::Styles.define :sidebar do
|
|
19
19
|
opaque: true
|
20
20
|
|
21
21
|
style :action_title,
|
22
|
-
background_color:
|
22
|
+
background_color: MP::Config.color.base,
|
23
23
|
text_color: :white,
|
24
24
|
top: 10,
|
25
25
|
width: 320,
|
data/lib/motion-prime.rb
CHANGED
data/motion-prime/config/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
module ElementTextHeightMixin
|
3
|
-
def
|
3
|
+
def content_height
|
4
|
+
return 0 if computed_options[:text].blank?
|
4
5
|
width = computed_options[:width]
|
5
6
|
font = computed_options[:font] || :system.uifont
|
6
7
|
raise "Please set element width for height calculation" unless width
|
@@ -9,9 +10,8 @@ module MotionPrime
|
|
9
10
|
lineBreakMode: UILineBreakModeWordWrap).height
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
-
|
14
|
-
computed_options[:bottom].to_i
|
13
|
+
def content_outer_height
|
14
|
+
content_height + computed_inner_top + computed_inner_bottom
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -8,13 +8,14 @@ module MotionPrime
|
|
8
8
|
include HasNormalizer
|
9
9
|
|
10
10
|
attr_accessor :options, :section, :name,
|
11
|
-
:view_class, :view, :styles, :screen
|
11
|
+
:view_class, :view, :view_name, :styles, :screen
|
12
12
|
|
13
13
|
define_callbacks :render
|
14
14
|
|
15
15
|
def initialize(options = {})
|
16
16
|
@options = options
|
17
17
|
@section = options.delete(:section)
|
18
|
+
@observe_errors_for = options.delete(:observe_errors_for)
|
18
19
|
@name = options[:name]
|
19
20
|
@block = options.delete(:block)
|
20
21
|
@view_class = options.delete(:view_class) || "UIView"
|
@@ -39,7 +40,7 @@ module MotionPrime
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def compute_options!
|
42
|
-
@computed_options = options
|
43
|
+
@computed_options = normalize_options(options, section)
|
43
44
|
compute_block_options
|
44
45
|
compute_style_options
|
45
46
|
@computed_options = normalize_options(@computed_options, section)
|
@@ -56,9 +57,14 @@ module MotionPrime
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def compute_style_options
|
59
|
-
@styles = [
|
60
|
-
@styles
|
61
|
-
@styles
|
60
|
+
@styles = []
|
61
|
+
@styles << :"#{section.name}_#{name}" if section.present?
|
62
|
+
@styles << :"base_#{@view_name}"
|
63
|
+
if section && @observe_errors_for && @observe_errors_for.errors[section.name].present?
|
64
|
+
@styles << :"base_#{name}_with_errors"
|
65
|
+
end
|
66
|
+
custom_styles = @computed_options.delete(:styles)
|
67
|
+
@styles += [*custom_styles]
|
62
68
|
@computed_options.merge!(style_options)
|
63
69
|
end
|
64
70
|
|
@@ -18,46 +18,125 @@ module MotionPrime
|
|
18
18
|
view.bounds.size.height
|
19
19
|
end
|
20
20
|
|
21
|
+
def computed_padding_left
|
22
|
+
computed_options[:padding_left] ||
|
23
|
+
computed_options[:padding] || 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def computed_padding_right
|
27
|
+
computed_options[:padding_right] ||
|
28
|
+
computed_options[:padding] || 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def computed_padding_top
|
32
|
+
computed_options[:padding_top] ||
|
33
|
+
computed_options[:padding] || 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def computed_padding_bottom
|
37
|
+
computed_options[:padding_bottom] ||
|
38
|
+
computed_options[:padding] || 0
|
39
|
+
end
|
40
|
+
|
21
41
|
def computed_width
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
width
|
28
|
-
|
29
|
-
|
42
|
+
@computed_width ||= begin
|
43
|
+
width = computed_options[:width]
|
44
|
+
width = 0.0 if width.nil?
|
45
|
+
|
46
|
+
# calculate width if width is relative, e.g 0.7
|
47
|
+
if width > 0 && width <= 1
|
48
|
+
width * computed_max_width
|
49
|
+
else
|
50
|
+
width > computed_max_width ? computed_max_width : width
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# content width + content padding
|
56
|
+
def computed_outer_width
|
57
|
+
@computed_outer_width ||= begin
|
58
|
+
computed_width + computed_padding_left + computed_padding_right
|
30
59
|
end
|
31
60
|
end
|
32
61
|
|
33
62
|
def computed_height
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
height
|
40
|
-
|
41
|
-
|
63
|
+
@computed_height ||= begin
|
64
|
+
height = computed_options[:height]
|
65
|
+
height = 0.0 if height.nil?
|
66
|
+
|
67
|
+
# calculate height if height is relative, e.g 0.7
|
68
|
+
if height > 0 && height <= 1
|
69
|
+
height * computed_max_height
|
70
|
+
else
|
71
|
+
height > computed_max_height ? computed_max_height : height
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# content height + content padding
|
77
|
+
def computed_outer_height
|
78
|
+
@computed_outer_height ||= begin
|
79
|
+
computed_height + computed_padding_top + computed_padding_bottom
|
42
80
|
end
|
43
81
|
end
|
44
82
|
|
45
83
|
def computed_left
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
84
|
+
@computed_left ||= begin
|
85
|
+
left = computed_options[:left]
|
86
|
+
right = computed_options[:right]
|
87
|
+
return left if left
|
88
|
+
return 0 if right.nil?
|
50
89
|
|
51
|
-
|
90
|
+
computed_max_width - (computed_width + right)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# content left + content padding
|
95
|
+
def computed_inner_left
|
96
|
+
@computed_inner_left ||= begin
|
97
|
+
computed_left + computed_padding_left
|
98
|
+
end
|
52
99
|
end
|
53
100
|
|
54
101
|
def computed_top
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
102
|
+
@computed_top ||= begin
|
103
|
+
top = computed_options[:top]
|
104
|
+
bottom = computed_options[:bottom]
|
105
|
+
return top if top
|
106
|
+
return 0 if bottom.nil?
|
107
|
+
|
108
|
+
computed_max_height - (computed_height + bottom)
|
109
|
+
end
|
110
|
+
end
|
59
111
|
|
60
|
-
|
112
|
+
# content top + content padding
|
113
|
+
def computed_inner_top
|
114
|
+
@computed_inner_top ||= begin
|
115
|
+
computed_top + computed_padding_top
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def computed_bottom
|
120
|
+
computed_options[:bottom] || 0
|
121
|
+
end
|
122
|
+
|
123
|
+
def computed_inner_bottom
|
124
|
+
computed_bottom + computed_padding_bottom
|
125
|
+
end
|
126
|
+
|
127
|
+
def computed_right
|
128
|
+
computed_options[:right] || 0
|
129
|
+
end
|
130
|
+
|
131
|
+
def computed_inner_right
|
132
|
+
computed_right + computed_padding_right
|
133
|
+
end
|
134
|
+
|
135
|
+
def reset_computed_values
|
136
|
+
[:left, :top, :right, :bottom, :width, :height].each do |key|
|
137
|
+
instance_variable_set "@compited_#{key}", nil
|
138
|
+
instance_variable_set "@compited_inner_#{key}", nil
|
139
|
+
end
|
61
140
|
end
|
62
141
|
|
63
142
|
class << self
|
@@ -7,10 +7,19 @@ module MotionPrime
|
|
7
7
|
options = computed_options
|
8
8
|
return if options[:hidden]
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
size_to_fit_if_needed
|
11
|
+
|
12
|
+
# render background
|
13
|
+
bg_color = options[:background_color]
|
14
|
+
if bg_color
|
15
|
+
rect = CGRectMake(
|
16
|
+
computed_left, computed_top, computed_outer_width, computed_outer_height
|
17
|
+
)
|
18
|
+
bg_color.uicolor.setFill
|
19
|
+
UIRectFill(rect)
|
12
20
|
end
|
13
21
|
|
22
|
+
# render text
|
14
23
|
color = options[:text_color]
|
15
24
|
color.uicolor.set if color
|
16
25
|
font = options[:font] || :system
|
@@ -21,7 +30,8 @@ module MotionPrime
|
|
21
30
|
)
|
22
31
|
else
|
23
32
|
rect = CGRectMake(
|
24
|
-
|
33
|
+
computed_inner_left, computed_inner_top,
|
34
|
+
computed_width, computed_height
|
25
35
|
)
|
26
36
|
line_break = options.has_key?(:line_break_mode) ? options[:line_break_mode] : :wordwrap
|
27
37
|
alignment = options.has_key?(:text_alignment) ? options[:text_alignment] : :left
|
@@ -32,5 +42,12 @@ module MotionPrime
|
|
32
42
|
)
|
33
43
|
end
|
34
44
|
end
|
45
|
+
|
46
|
+
def size_to_fit_if_needed
|
47
|
+
if computed_options[:size_to_fit]
|
48
|
+
@computed_options[:height] = content_height
|
49
|
+
reset_computed_values
|
50
|
+
end
|
51
|
+
end
|
35
52
|
end
|
36
53
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MotionPrime
|
2
|
+
class ErrorMessageElement < BaseElement
|
3
|
+
include MotionPrime::ElementTextHeightMixin
|
4
|
+
|
5
|
+
after_render :size_to_fit
|
6
|
+
|
7
|
+
def view_class
|
8
|
+
"UILabel"
|
9
|
+
end
|
10
|
+
|
11
|
+
def size_to_fit
|
12
|
+
view.size.height = self.content_height
|
13
|
+
end
|
14
|
+
|
15
|
+
def computed_inner_top
|
16
|
+
computed_options[:top].to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def computed_inner_bottom
|
20
|
+
computed_options[:bottom].to_i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/motion-prime/models/base.rb
CHANGED
@@ -3,207 +3,23 @@ motion_require './bag.rb'
|
|
3
3
|
motion_require './finder.rb'
|
4
4
|
motion_require './model.rb'
|
5
5
|
motion_require './store.rb'
|
6
|
+
motion_require './sync.rb'
|
7
|
+
motion_require './association.rb'
|
6
8
|
motion_require './store_extension.rb'
|
7
9
|
module MotionPrime
|
8
10
|
class BaseModel < NSFNanoObject
|
9
|
-
class_attribute :_sync_url
|
10
|
-
class_attribute :_updatable_attributes
|
11
|
-
class_attribute :_associations
|
12
|
-
alias_method :attributes, :info
|
13
11
|
include MotionPrime::HasAuthorization
|
14
|
-
|
15
12
|
include MotionPrime::ModelMethods
|
16
|
-
extend MotionPrime::ModelClassMethods
|
17
|
-
|
18
|
-
extend MotionPrime::ModelFinderMethods
|
19
13
|
include MotionPrime::ModelAssociationMethods
|
14
|
+
include MotionPrime::ModelSyncMethods
|
20
15
|
|
16
|
+
extend MotionPrime::ModelClassMethods
|
17
|
+
extend MotionPrime::ModelFinderMethods
|
21
18
|
extend MotionPrime::ModelAssociationClassMethods
|
19
|
+
extend MotionPrime::ModelSyncClassMethods
|
22
20
|
|
23
|
-
def
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
def model_name
|
28
|
-
self.class.name.underscore
|
29
|
-
end
|
30
|
-
|
31
|
-
def new_record?
|
32
|
-
id.blank?
|
33
|
-
end
|
34
|
-
|
35
|
-
# destroy on server and delete on local
|
36
|
-
def destroy(&block)
|
37
|
-
use_callback = block_given?
|
38
|
-
api_client.delete(sync_url) do
|
39
|
-
block.call() if use_callback
|
40
|
-
end
|
41
|
-
delete
|
42
|
-
end
|
43
|
-
|
44
|
-
# sync with server and save on local
|
45
|
-
def sync!(sync_options = {}, &block)
|
46
|
-
sync(sync_options.merge(save: true), &block)
|
47
|
-
end
|
48
|
-
|
49
|
-
# sync with with server
|
50
|
-
# TODO: order of fetch/update should be based on updated time
|
51
|
-
def sync(sync_options = {}, &block)
|
52
|
-
use_callback = block_given?
|
53
|
-
should_fetch = sync_options[:fetch]
|
54
|
-
should_update = sync_options[:update]
|
55
|
-
|
56
|
-
should_fetch = false if sync_url.blank?
|
57
|
-
should_update = false if sync_url.blank?
|
58
|
-
|
59
|
-
should_fetch = !new_record? if should_fetch.nil?
|
60
|
-
should_update = new_record? if should_update.nil?
|
61
|
-
|
62
|
-
fetch_with_url self.sync_url do
|
63
|
-
save if sync_options[:save]
|
64
|
-
block.call if use_callback
|
65
|
-
end if should_fetch
|
66
|
-
update_with_url self.sync_url do
|
67
|
-
save if sync_options[:save]
|
68
|
-
|
69
|
-
# run callback only if it wasn't run on fetch
|
70
|
-
block.call if use_callback && !should_fetch
|
71
|
-
end if should_update
|
72
|
-
|
73
|
-
fetch_associations(sync_options) do
|
74
|
-
# run callback only if it wasn't run on fetch or update
|
75
|
-
block.call if use_callback && !should_fetch && !should_update
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# fetch from server using url
|
80
|
-
def fetch_with_url(url, &block)
|
81
|
-
api_client.get(url) do |data|
|
82
|
-
if data.present?
|
83
|
-
fetch_with_attributes(data, &block)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# update on server using url
|
89
|
-
def update_with_url(url, &block)
|
90
|
-
use_callback = block_given?
|
91
|
-
post_data = { model_name => filtered_updatable_attributes}
|
92
|
-
api_client.send(id ? :put : :post, url, post_data) do |data|
|
93
|
-
self.id ||= data['id']
|
94
|
-
block.call() if use_callback
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# set attributes, using fetch
|
99
|
-
def fetch_with_attributes(attrs, &block)
|
100
|
-
attrs.each do |key, value|
|
101
|
-
if respond_to?(:"fetch_#{key}")
|
102
|
-
self.send(:"fetch_#{key}", value)
|
103
|
-
elsif respond_to?(:"#{key}=")
|
104
|
-
self.send(:"#{key}=", value)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
block.call(self) if block_given?
|
108
|
-
end
|
109
|
-
|
110
|
-
def fetch_associations(sync_options = {}, &block)
|
111
|
-
use_callback = block_given?
|
112
|
-
associations = self.class._associations || {}
|
113
|
-
|
114
|
-
associations.keys.each_with_index do |key, index|
|
115
|
-
if use_callback && associations.count - 1 == index
|
116
|
-
fetch_association(key, sync_options, &block)
|
117
|
-
else
|
118
|
-
fetch_association(key, sync_options)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def fetch_association(key, sync_options = {}, &block)
|
124
|
-
options = self.class._associations[key]
|
125
|
-
return unless options[:sync_url]
|
126
|
-
options[:type] == :many ?
|
127
|
-
fetch_has_many(key, options, sync_options, &block) :
|
128
|
-
fetch_has_one(key, options, sync_options, &block)
|
129
|
-
end
|
130
|
-
|
131
|
-
def fetch_has_many(key, options = {}, sync_options = {}, &block)
|
132
|
-
old_collection = self.send(key)
|
133
|
-
use_callback = block_given?
|
134
|
-
puts "SYNC: started sync for #{key} in #{self.class.name}"
|
135
|
-
api_client.get normalize_sync_url(options[:sync_url]) do |data|
|
136
|
-
data = data[options[:sync_key]] if options[:sync_key]
|
137
|
-
if data.present?
|
138
|
-
# Update/Create existing records
|
139
|
-
data.each do |attributes|
|
140
|
-
model = old_collection.detect{ |model| model.id == attributes[:id]}
|
141
|
-
unless model
|
142
|
-
model = key.singularize.to_s.classify.constantize.new
|
143
|
-
self.send(:"#{key}_bag") << model
|
144
|
-
end
|
145
|
-
model.fetch_with_attributes(attributes)
|
146
|
-
model.save if sync_options[:save]
|
147
|
-
end
|
148
|
-
old_collection.each do |old_model|
|
149
|
-
model = data.detect{ |model| model[:id] == old_model.id}
|
150
|
-
unless model
|
151
|
-
old_model.delete
|
152
|
-
end
|
153
|
-
end
|
154
|
-
save if sync_options[:save]
|
155
|
-
puts "SYNC: finished sync for #{key} in #{self.class.name}"
|
156
|
-
block.call if use_callback
|
157
|
-
else
|
158
|
-
puts "SYNC ERROR: failed sync for #{key} in #{self.class.name}"
|
159
|
-
block.call if use_callback
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def fetch_has_one(key, options = {}, &block)
|
165
|
-
# TODO: add implementation
|
166
|
-
end
|
167
|
-
|
168
|
-
def inspect
|
169
|
-
"#<#{self.class}:0x#{self.object_id.to_s(16)}> " + MotionPrime::JSON.generate(attributes)
|
170
|
-
end
|
171
|
-
|
172
|
-
def filtered_updatable_attributes
|
173
|
-
return attributes if self.class.updatable_attributes.blank?
|
174
|
-
self.class.updatable_attributes.to_a.inject({}) do |hash, attribute|
|
175
|
-
key, options = *attribute
|
176
|
-
return hash if options[:if] && !send(options[:if])
|
177
|
-
if block = options[:block]
|
178
|
-
value = instance_eval(&block)
|
179
|
-
else
|
180
|
-
value = attributes[key]
|
181
|
-
end
|
182
|
-
hash.merge!(key => value)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def normalize_sync_url(url)
|
187
|
-
url.to_s.gsub(':id', id.to_s)
|
188
|
-
end
|
189
|
-
|
190
|
-
class << self
|
191
|
-
def sync_url(url = nil)
|
192
|
-
url ? self._sync_url = url : self._sync_url
|
193
|
-
end
|
194
|
-
|
195
|
-
def updatable_attributes(*attrs)
|
196
|
-
return self._updatable_attributes if attrs.blank?
|
197
|
-
attrs.each do |attribute|
|
198
|
-
updatable_attribute attribute
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def updatable_attribute(attribute, options = {}, &block)
|
203
|
-
options[:block] = block if block_given?
|
204
|
-
self._updatable_attributes ||= {}
|
205
|
-
self._updatable_attributes[attribute] = options
|
206
|
-
end
|
21
|
+
def errors
|
22
|
+
@errors ||= Errors.new(self)
|
207
23
|
end
|
208
24
|
end
|
209
25
|
end
|