gyro 0.4.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.
@@ -0,0 +1,67 @@
1
+ =begin
2
+ Copyright 2016 - Niji
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ module Gyro
18
+ module Realm
19
+ module Java
20
+ module Templates
21
+
22
+ # ANNOTATIONS
23
+ PRIMARY_KEY_ANNOTATION = '@PrimaryKey'
24
+ INDEXED_ANNOTATION = '@Index'
25
+ IGNORED_ANNOTATION = '@Ignore'
26
+ GSON_ANNOTATION = "@SerializedName(\"%s\")"
27
+ SUPPORT_ANNOTATION = "@android.support.annotation.%s"
28
+
29
+ # COMMONS
30
+ PACKAGE_TEMPLATE = 'package %s;'
31
+ JAVA_FILE_TEMPLATE = '%s.java'
32
+ GENERATED_MESSAGE = '/* DO NOT EDIT | Generated by gyro */'
33
+
34
+ # IMPORTS
35
+ IMPORT_DATE = 'import java.util.Date;'
36
+ IMPORT_LIST = 'import java.util.List;'
37
+ IMPORT_GSON = 'import com.google.gson.annotations.SerializedName;'
38
+ IMPORT_REALM_LIST = 'import io.realm.RealmList;'
39
+ IMPORT_REALM_OBJECT = 'import io.realm.RealmObject;'
40
+ IMPORT_REALM_IGNORE = 'import io.realm.annotations.Ignore;'
41
+ IMPORT_REALM_INDEX = 'import io.realm.annotations.Index;'
42
+ IMPORT_REALM_PRIMARY_KEY = 'import io.realm.annotations.PrimaryKey;'
43
+
44
+ # ENUM
45
+ ENUM_TEMPLATE = 'public enum %s {'
46
+ ENUM_JSON_VALUE = "(\"%s\")"
47
+
48
+ # CLASS
49
+ CLASS_TEMPLATE = 'public class %s extends RealmObject {'
50
+ ATTRIBUTE_TEMPLATE = 'private %s %s;'
51
+ FINAL_ATTRIBUTE_TEMPLATE = 'private final %s %s;'
52
+ REALM_LIST_TEMPLATE = 'RealmList<%s>'
53
+ LIST_TEMPLATE = 'List<%s>'
54
+
55
+ # CONSTANTS
56
+ ATTRIBUTE_CONSTANTS = 'public interface Attributes {'
57
+ RELATIONSHIP_CONSTANTS = 'public interface Relationships {'
58
+ CONSTANT_TEMPLATE = 'String %s = "%s";'
59
+
60
+ # COMMENTS
61
+ CLASS_COMMENT_TEMPLATE = "/**\n * %s\n */"
62
+ ATTRIBUTE_COMMENT_TEMPLATE = '/** %s */'
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ =begin
2
+ Copyright 2016 - Niji
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ module Gyro
18
+ module Realm
19
+ module ObjC
20
+ module Converter
21
+
22
+ TYPES = {
23
+ :integer_16 => 'int',
24
+ :integer_32 => 'long',
25
+ :integer_64 => 'long long',
26
+ :decimal => 'double',
27
+ :double => 'double',
28
+ :float => 'float',
29
+ :string => 'NSString *',
30
+ :boolean => 'BOOL',
31
+ :date => 'NSDate *',
32
+ :binary => 'NSData *'
33
+ }
34
+
35
+ DEFAULTS = {
36
+ :integer_16 => '@(0)',
37
+ :integer_32 => '@(0)',
38
+ :integer_64 => '@(0)',
39
+ :decimal => '@(0.0)',
40
+ :double => '@(0.0)',
41
+ :float => '@(0.0)',
42
+ :string => '@""',
43
+ :boolean => '@(NO)',
44
+ :date => '[NSDate date]',
45
+ :binary => '[NSData new]'
46
+ }
47
+
48
+ def is_number_type?(type)
49
+ [:integer_16, :integer_32, :integer_64, :decimal, :double, :float].include?(type)
50
+ end
51
+
52
+ def convert_type(type, use_nsnumber = false)
53
+ use_nsnumber && is_number_type?(type) ? 'NSNumber *' : TYPES[type]
54
+ end
55
+
56
+ def convert_default(type)
57
+ DEFAULTS[type]
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ =begin
2
+ Copyright 2016 - Niji
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ require File.expand_path('templates', File.dirname(__FILE__))
18
+ require File.expand_path('converter', File.dirname(__FILE__))
19
+ require File.expand_path('../../utils/string_xcdatamodel', File.dirname(__FILE__))
20
+ require File.expand_path('../../utils/file_utils', File.dirname(__FILE__))
21
+
22
+ module Gyro
23
+ module Realm
24
+ module ObjC
25
+ module EnumGenerator
26
+
27
+ # INCLUDES #############################################################
28
+
29
+ include Templates
30
+ include Converter
31
+
32
+ # PUBLIC METHODS #######################################################
33
+
34
+ def generate_enum_file(path, xcdatamodel)
35
+ enums = []
36
+ enum_file = String.new
37
+ enum_file << GENERATED_MESSAGE + "\n"
38
+ enum_file << "\n" + SEPARATOR + "\n\n"
39
+ enum_file << PRAGMA_MARK_TYPES + "\n\n"
40
+ xcdatamodel.entities.each do |_, entity|
41
+ entity.attributes.each do |_, attribute|
42
+ if attribute.enum? and !enums.include?(attribute.enum_type)
43
+ int_type = convert_type(attribute.type)
44
+ enum_type = attribute.enum_type
45
+ enum_file << "\n" if enums.length > 0
46
+ enums.push(enum_type)
47
+ enum = generate_enum(int_type, enum_type, attribute)
48
+ enum_file << enum
49
+ end
50
+ end
51
+ end
52
+ if enums.size != 0
53
+ Gyro.write_file_with_name(path, HEADER_TEMPLATE%[ENUM_FILE_NAME], enum_file)
54
+ end
55
+ end
56
+
57
+ private ################################################################
58
+
59
+ def generate_enum(int_type, enum_name, attribute)
60
+ enum_string = String.new
61
+ enum_string << ENUM_TYPEDEF_TEMPLATE%[int_type, enum_name] + "\n"
62
+ enum_values = Array.new
63
+ enum_values += %W(#{enum_name}None) if attribute.optional?
64
+ enum_values += attribute.enum_values
65
+ if enum_values.length != 0
66
+ # First one
67
+ value = enum_values[0]
68
+ enum_string << ' ' + value + ' = 0,' + "\n"
69
+ # Others
70
+ (1..enum_values.length - 2).each { |i|
71
+ value = enum_values[i]
72
+ enum_string << ' ' + value + ',' + "\n"
73
+ }
74
+ # Last one if at least 2 values
75
+ if enum_values.length > 1
76
+ value = enum_values.last
77
+ enum_string << ' ' + value + "\n"
78
+ end
79
+ end
80
+ enum_string << '};' + "\n"
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,373 @@
1
+ =begin
2
+ Copyright 2016 - Niji
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ require File.expand_path('../../utils/log', File.dirname(__FILE__))
18
+ require File.expand_path('../../utils/string_xcdatamodel', File.dirname(__FILE__))
19
+ require File.expand_path('../../utils/file_utils', File.dirname(__FILE__))
20
+ require File.expand_path('../../xcdatamodel/parser/relationship', File.dirname(__FILE__))
21
+ require File.expand_path('converter', File.dirname(__FILE__))
22
+ require File.expand_path('templates', File.dirname(__FILE__))
23
+ require File.expand_path('protocol_generator', File.dirname(__FILE__))
24
+ require File.expand_path('enum_generator', File.dirname(__FILE__))
25
+ require File.expand_path('json_category_generator', File.dirname(__FILE__))
26
+
27
+ module Gyro
28
+ module Realm
29
+ module ObjC
30
+
31
+ class Generator
32
+
33
+ # INCLUDES #############################################################
34
+
35
+ include Gyro::XCDataModel::Parser
36
+ include Converter
37
+ include Templates
38
+ include ProtocolGenerator
39
+ include EnumGenerator
40
+ include JSONCategoryGenerator
41
+
42
+ # PUBLIC METHODS #######################################################
43
+
44
+ def initialize(path, xcdatamodel, json = false, framework = false, use_nsnumber = false)
45
+ generate_class_files(path, xcdatamodel, use_nsnumber)
46
+ generate_protocol_file(path, xcdatamodel)
47
+ generate_enum_file(path, xcdatamodel)
48
+ generate_objc_categories(path, xcdatamodel, framework) if json
49
+ end
50
+
51
+ private ################################################################
52
+
53
+ def generate_class_files(path, xcdatamodel, use_nsnumber)
54
+ puts "\n"
55
+ Gyro::Log::title('Objc Realm')
56
+ xcdatamodel.entities.each do |_, entity|
57
+ unless entity.abstract?
58
+ Gyro::Log::success("Generating entity #{entity.name}...")
59
+ generate_class(path, entity, use_nsnumber)
60
+ end
61
+ end
62
+ end
63
+
64
+ def generate_class(path, entity, use_nsnumber)
65
+ header_file = generate_header_file(entity, use_nsnumber)
66
+ source_file = generate_source_file(entity, use_nsnumber)
67
+ Gyro.write_file_with_name(path, HEADER_TEMPLATE%[entity.name], header_file)
68
+ Gyro.write_file_with_name(path, SOURCE_TEMPLATE%[entity.name], source_file)
69
+ end
70
+
71
+ def generate_header_file(entity, use_nsnumber)
72
+ header_file = String.new
73
+ header_file << GENERATED_MESSAGE + "\n"
74
+ header_file << "\n" + SEPARATOR + "\n\n"
75
+ header_file << PRAGMA_MARK_IMPORTS + "\n\n"
76
+ header_file << IMPORT_REALM + "\n"
77
+ header_file << IMPORT_HEADER%[ENUM_FILE_NAME] + "\n" if require_enum_import(entity)
78
+ header_file << generate_import_protocols(entity)
79
+ header_file << generate_class_types(entity)
80
+ header_file << generate_header_constants(entity)
81
+ header_file << "\n" + SEPARATOR + "\n\n"
82
+ header_file << PRAGMA_MARK_INTERFACE + "\n\n"
83
+ header_file << CLASS_COMMENT_TEMPLATE%[entity.comment] + "\n" unless entity.comment.empty?
84
+ header_file << INTERFACE_TEMPLATE%[entity.name] + "\n"
85
+ header_file << generate_properties(entity, use_nsnumber)
86
+ header_file << "\n" << END_CODE + "\n"
87
+ end
88
+
89
+ def generate_properties(entity, use_nsnumber)
90
+ header_file = String.new
91
+ header_file << "\n" + PRAGMA_MARK_PROPERTIES + "\n\n"
92
+ entity.attributes.each do |_, attribute|
93
+ header_file << PROPERTY_COMMENT_TEMPLATE%[attribute.comment] + "\n" unless attribute.comment.empty?
94
+ name = attribute.name
95
+ use_nsnumber_wrapper = use_nsnumber && require_nsnumber_wrapper(attribute)
96
+ type = attribute.enum? ? attribute.enum_type : convert_type(attribute.type, use_nsnumber_wrapper)
97
+ if type.nil?
98
+ Gyro::Log::error("The property #{name} of entity #{entity.name} has an Undefined type.")
99
+ type = 'id'
100
+ end
101
+ type = '(readonly) ' + type unless attribute.realm_read_only.empty?
102
+ header_file << SIMPLE_PROPERTY_TEMPLATE%[type, type.end_with?('*') ? name : ' ' + name] + "\n"
103
+ if use_nsnumber_wrapper
104
+ num_type = convert_type(attribute.type)
105
+ header_file << NUMBER_ACCESSOR_DECL_TEMPLATES%[num_type, name, name.capitalize_first_letter, num_type]
106
+ end
107
+ end
108
+ entity.relationships.each do |_, relationship|
109
+ is_list = relationship.type == :to_many
110
+ if relationship.inverse?
111
+ type = '(readonly) ' + (is_list ? 'NSArray' : relationship.inverse_type)
112
+ name = relationship.name.delete_inverse_suffix
113
+ else
114
+ if relationship.destination.empty?
115
+ type = is_list ? REALM_LIST_TEMPLATE%[relationship.inverse_type] : relationship.inverse_type
116
+ else
117
+ type = LIST_TEMPLATE%[convert_type(relationship.destination.downcase.to_sym)]
118
+ end
119
+ name = relationship.name
120
+ end
121
+ header_file << OBJECT_PROPERTY_TEMPLATE%[type, name] + "\n"
122
+ end
123
+ header_file
124
+ end
125
+
126
+ def require_nsnumber_wrapper(attribute)
127
+ !attribute.enum? && attribute.realm_read_only.empty? && is_number_type?(attribute.type)
128
+ end
129
+
130
+ def require_enum_import(entity)
131
+ entity.attributes.each do |_, attribute|
132
+ if attribute.enum?
133
+ return true
134
+ end
135
+ end
136
+ false
137
+ end
138
+
139
+ def generate_import_protocols(entity)
140
+ entity.has_list_attributes?(true) ? IMPORT_HEADER%[PROTOCOL_FILE_NAME] + "\n" : ''
141
+ end
142
+
143
+ def generate_class_types(entity)
144
+ class_types = String.new
145
+ entity.relationships.each do |_, relationship|
146
+ class_types << CLASS_TEMPLATE%[relationship.inverse_type] + "\n" if relationship.inverse_type != entity.name && relationship.destination.empty?
147
+ end
148
+ class_types.empty? ? class_types : "\n" + PRAGMA_MARK_TYPES + "\n\n" + class_types
149
+ end
150
+
151
+ def generate_header_constants(entity)
152
+ constants = String.new
153
+ unless entity.attributes.empty?
154
+ name = CONSTANT_ATTRIBUTES_NAME%[entity.name]
155
+ constants << CONSTANT_HEADER_ATTRIBUTES%[name, name] + "\n"
156
+ entity.attributes.each do |_, attribute|
157
+ constants << ' ' + CONSTANT_HEADER_ITEM%[attribute.name] + "\n"
158
+ end
159
+ constants << "} #{name};\n"
160
+ end
161
+ if entity.has_no_inverse_relationship?
162
+ constants << "\n" unless constants.empty?
163
+ name = CONSTANT_RELATIONSHIPS_NAME%[entity.name]
164
+ constants << CONSTANT_HEADER_RELATIONSHIPS%[name] + "\n"
165
+ entity.relationships.each do |_, relationship|
166
+ constants << ' ' + CONSTANT_HEADER_ITEM%[relationship.name] + "\n" unless relationship.inverse?
167
+ end
168
+ constants << "} #{name};\n"
169
+ end
170
+ constants.empty? ? constants : "\n" + PRAGMA_MARK_CONSTANTS + "\n\n"+ constants
171
+ end
172
+
173
+ def generate_source_file(entity, use_nsnumber)
174
+ source_file = String.new
175
+ source_file << GENERATED_MESSAGE + "\n"
176
+ source_file << "\n" + SEPARATOR + "\n\n"
177
+ source_file << PRAGMA_MARK_IMPORTS + "\n\n"
178
+ source_file << IMPORT_HEADER%[entity.name] + "\n"
179
+ source_file << generate_source_constants(entity)
180
+ source_file << "\n" + SEPARATOR + "\n\n"
181
+ source_file << PRAGMA_MARK_IMPLEMENTATION + "\n\n"
182
+ source_file << IMPLEMENTATION_TEMPLATE%[entity.name] + "\n"
183
+ source_file << generate_numbers_accessors(entity) if use_nsnumber
184
+ if require_overriding(entity)
185
+ source_file << "\n" + PRAGMA_MARK_SUPER + "\n"
186
+ source_file << generate_primary_key(entity)
187
+ source_file << generate_required_properties(entity)
188
+ source_file << generate_default_values(entity)
189
+ source_file << generate_ignored_properties(entity)
190
+ source_file << generate_read_only_properties(entity, use_nsnumber)
191
+ source_file << generate_inverse_properties(entity)
192
+ end
193
+ source_file << "\n" << END_CODE + "\n"
194
+ end
195
+
196
+ def generate_source_constants(entity)
197
+ constants = String.new
198
+ unless entity.attributes.empty?
199
+ name = CONSTANT_ATTRIBUTES_NAME%[entity.name]
200
+ constants << CONSTANT_SOURCE_ATTRIBUTES%[name, name] + "\n"
201
+ entity.attributes.each_with_index do |(_, attribute), idx|
202
+ constants << ',' + "\n" unless idx == 0
203
+ constants << ' ' + CONSTANT_SOURCE_ITEM%[attribute.name, attribute.name]
204
+ constants << "\n" if idx == entity.attributes.length - 1
205
+ end
206
+ constants << '};' + "\n"
207
+ end
208
+ if entity.has_no_inverse_relationship?
209
+ constants << "\n" unless constants.empty?
210
+ name = CONSTANT_RELATIONSHIPS_NAME%[entity.name]
211
+ constants << CONSTANT_SOURCE_RELATIONSHIPS%[name, name] + "\n"
212
+ has_first = false
213
+ entity.relationships.each_with_index do |(_, relationship), idx|
214
+ unless relationship.inverse?
215
+ constants << ',' + "\n" if has_first
216
+ constants << ' ' + CONSTANT_SOURCE_ITEM%[relationship.name, relationship.name]
217
+ has_first = true
218
+ end
219
+ constants << "\n" if idx == entity.relationships.length - 1
220
+ end
221
+ constants << '};' + "\n"
222
+ end
223
+ constants.empty? ? constants : "\n" + PRAGMA_MARK_CONSTANTS + "\n\n" + constants
224
+ end
225
+
226
+ def generate_numbers_accessors(entity)
227
+ number_accessors = String.new
228
+ entity.attributes.each do |_, attribute|
229
+ if require_nsnumber_wrapper(attribute)
230
+ type = convert_type(attribute.type)
231
+ name = attribute.name
232
+ selector = type.gsub(/ /, '') + 'Value'
233
+ number_accessors << NUMBER_ACCESSOR_SOURCE_TEMPLATES%[type, name, name, selector, name.capitalize_first_letter, type, name] + "\n"
234
+ end
235
+ end
236
+ number_accessors.empty? ? "" : "\n" + PRAGMA_MARK_NUMBER_ACCESSORS + "\n\n" + number_accessors
237
+ end
238
+
239
+ def require_overriding(entity)
240
+ if entity.has_primary_key? or entity.attributes.count > 0
241
+ return true
242
+ end
243
+ false
244
+ end
245
+
246
+ def generate_primary_key(entity)
247
+ primary_key = String.new
248
+ if entity.has_primary_key?
249
+ primary_key << "\n" + '+ (NSString *)primaryKey' + "\n"
250
+ primary_key << '{' + "\n"
251
+ primary_key << ' ' + "return @\"" + entity.identity_attribute + "\";" + "\n"
252
+ primary_key << '}' + "\n"
253
+ end
254
+ primary_key
255
+ end
256
+
257
+ def generate_required_properties(entity)
258
+ required_properties = String.new
259
+ if entity.has_required?
260
+ required_properties << "\n" + '// Specify required properties' + "\n"
261
+ required_properties << '+ (NSArray *)requiredProperties' + "\n"
262
+ required_properties << '{' + "\n"
263
+ required_properties << ' ' + 'return @['
264
+ entity.attributes.each do |_, attribute|
265
+ required_properties << ARRAY_TEMPLATE%[attribute.name.add_quotes] if entity.is_required?(attribute)
266
+ end
267
+ required_properties = required_properties[0..required_properties.length - 3] # delete last coma
268
+ required_properties << '];' + "\n"
269
+ required_properties << '}' + "\n"
270
+ end
271
+ required_properties
272
+ end
273
+
274
+ def generate_default_values(entity)
275
+ default_values = String.new
276
+ if entity.has_required?
277
+ default_values << "\n" + '// Specify default values for required properties' + "\n"
278
+ default_values << '+ (NSDictionary *)defaultPropertyValues' + "\n"
279
+ default_values << '{' + "\n"
280
+ default_values << ' ' + 'return @{'
281
+ entity.attributes.each do |_, attribute|
282
+ if entity.is_required?(attribute)
283
+ default_value = convert_default(attribute.type)
284
+ if entity.has_default_value?(attribute) && !attribute.default.empty?
285
+ default_value = attribute.type == :string ? "@\"#{attribute.default})\"" : "@(#{attribute.default})"
286
+ end
287
+ default_values << DICTIONARY_DEFAULT%[attribute.name.add_quotes, default_value] + ' '
288
+ end
289
+ end
290
+ default_values = default_values[0..default_values.length - 3] # delete last coma
291
+ default_values << '};' + "\n"
292
+ default_values << '}' + "\n"
293
+ end
294
+ default_values
295
+ end
296
+
297
+ def generate_ignored_properties(entity)
298
+ ignored_properties = String.new
299
+ if entity.has_ignored?
300
+ ignored_properties << "\n" + "// Specify properties to ignore (Realm won't persist these)" + "\n"
301
+ ignored_properties << '+ (NSArray *)ignoredProperties' + "\n"
302
+ ignored_properties << '{' + "\n"
303
+ ignored_properties << ' ' + 'return @['
304
+ entity.attributes.each do |_, attribute|
305
+ ignored_properties << ARRAY_TEMPLATE%[attribute.name.add_quotes] if attribute.realm_ignored?
306
+ end
307
+ entity.relationships.each do |_, relationship|
308
+ ignored_properties << ARRAY_TEMPLATE%[relationship.name.add_quotes] if relationship.realm_ignored?
309
+ end
310
+ ignored_properties = ignored_properties[0..ignored_properties.length - 3] # delete last coma
311
+ ignored_properties << '];' + "\n"
312
+ ignored_properties << '}' + "\n"
313
+ end
314
+ ignored_properties
315
+ end
316
+
317
+ def generate_read_only_properties(entity, use_nsnumber)
318
+ read_only_properties = String.new
319
+ entity.attributes.each do |_, attribute|
320
+ unless attribute.realm_read_only.empty?
321
+ type = attribute.enum? ? attribute.enum_type : convert_type(attribute.type, use_nsnumber)
322
+ read_only_properties << "\n" + READ_ONLY_DEF_TEMPLATE%[type, attribute.name] + "\n"
323
+ read_only_properties << '{' + "\n"
324
+ read_only_properties << ' ' + attribute.realm_read_only + "\n"
325
+ read_only_properties << '}' + "\n"
326
+ end
327
+ end
328
+ read_only_properties
329
+ end
330
+
331
+ def generate_inverse_properties(entity)
332
+ inverse_properties = String.new
333
+ entity.relationships.each do |_, relationship|
334
+ if relationship.inverse?
335
+ if relationship.type == :to_many
336
+ definition = INVERSE_DEF_TEMPLATE%['NSArray', relationship.name.delete_inverse_suffix]
337
+ value = INVERSE_MANY_TEMPLATE%[relationship.inverse_type, relationship.inverse_name]
338
+ else
339
+ definition = INVERSE_DEF_TEMPLATE%[relationship.inverse_type, relationship.name.delete_inverse_suffix]
340
+ value = INVERSE_ONE_TEMPLATE%[relationship.inverse_type, relationship.inverse_name]
341
+ end
342
+ inverse_properties << "\n" + definition + "\n"
343
+ inverse_properties << '{' + "\n"
344
+ inverse_properties << ' ' + value + "\n"
345
+ inverse_properties << '}' + "\n"
346
+ end
347
+ end
348
+ inverse_properties
349
+ end
350
+
351
+ def generate_indexed_properties(entity)
352
+ indexed_properties = String.new
353
+ if entity.has_indexed_attributes?
354
+ indexed_properties << "\n" + '// Specify properties to index' + "\n"
355
+ indexed_properties << '+ (NSArray *)ignoredProperties' + "\n"
356
+ indexed_properties << '{' + "\n"
357
+ indexed_properties << ' ' + 'return @['
358
+ entity.attributes.each do |_, attribute|
359
+ if attribute.indexed
360
+ indexed_properties << ARRAY_TEMPLATE%[attribute.name.add_quotes]
361
+ end
362
+ end
363
+ indexed_properties = indexed_properties[0..indexed_properties.length - 3] # delete last coma
364
+ indexed_properties << '];' + "\n"
365
+ indexed_properties << '}' + "\n"
366
+ end
367
+ indexed_properties
368
+ end
369
+
370
+ end
371
+ end
372
+ end
373
+ end