modelmaker 0.1.2
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.
- data/src/bin/modelmake +5 -0
- data/src/lib/modelmaker.rb +386 -0
- data/src/templates/builder_header.erb +27 -0
- data/src/templates/builder_implementation.erb +36 -0
- data/src/templates/header.erb +27 -0
- data/src/templates/implementation.erb +38 -0
- metadata +53 -0
data/src/bin/modelmake
ADDED
@@ -0,0 +1,386 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module ModelMaker
|
6
|
+
class Project
|
7
|
+
attr_accessor :name, :copyright, :class_prefix, :entities
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@entities = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_entity(entity)
|
14
|
+
entity.project = self
|
15
|
+
@entities << entity
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ProjectBuilder
|
20
|
+
def initialize(project)
|
21
|
+
@project = project
|
22
|
+
end
|
23
|
+
|
24
|
+
def project(name)
|
25
|
+
@project.name = name
|
26
|
+
end
|
27
|
+
|
28
|
+
def class_prefix(prefix)
|
29
|
+
@project.class_prefix = prefix
|
30
|
+
end
|
31
|
+
|
32
|
+
def copyright(copyright)
|
33
|
+
@project.copyright = copyright
|
34
|
+
end
|
35
|
+
|
36
|
+
def object(name, &configuration)
|
37
|
+
builder = EntityBuilder.new(name, &configuration)
|
38
|
+
@project.add_entity(builder.entity)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class EntityBuilder
|
43
|
+
attr_reader :entity
|
44
|
+
|
45
|
+
def initialize(entity_name, &configuration)
|
46
|
+
@entity = Entity.new(entity_name)
|
47
|
+
instance_eval(&configuration)
|
48
|
+
end
|
49
|
+
|
50
|
+
def inherits(superclass)
|
51
|
+
@entity.superclass = superclass
|
52
|
+
end
|
53
|
+
|
54
|
+
def conforms_to(protocol)
|
55
|
+
@entity.protocols << protocol
|
56
|
+
end
|
57
|
+
|
58
|
+
# There was a way to do that better... "define_all" or something
|
59
|
+
def string(propname)
|
60
|
+
add_property(StringProperty.new(propname))
|
61
|
+
end
|
62
|
+
|
63
|
+
def int(propname)
|
64
|
+
add_property(IntegerProperty.new(propname))
|
65
|
+
end
|
66
|
+
|
67
|
+
def set(propname)
|
68
|
+
add_property(SetProperty.new(propname))
|
69
|
+
end
|
70
|
+
|
71
|
+
def url(propname)
|
72
|
+
add_property(UrlProperty.new(propname))
|
73
|
+
end
|
74
|
+
|
75
|
+
def array(propname)
|
76
|
+
add_property(ArrayProperty.new(propname))
|
77
|
+
end
|
78
|
+
|
79
|
+
def date(propname)
|
80
|
+
add_property(DateProperty.new(propname))
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_property(property)
|
84
|
+
@entity.add_property(property)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Entity
|
89
|
+
attr_reader :name
|
90
|
+
attr_accessor :superclass, :protocols, :project
|
91
|
+
|
92
|
+
def initialize(name)
|
93
|
+
@name = name
|
94
|
+
|
95
|
+
@superclass = 'NSObject'
|
96
|
+
@properties = {}
|
97
|
+
@protocols = []
|
98
|
+
end
|
99
|
+
|
100
|
+
def short_name
|
101
|
+
@name
|
102
|
+
end
|
103
|
+
|
104
|
+
def class_name
|
105
|
+
if @project
|
106
|
+
"#{@project.class_prefix}#{@name}"
|
107
|
+
else
|
108
|
+
@name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
alias :name :class_name
|
113
|
+
|
114
|
+
def instance_name
|
115
|
+
name = @name.clone
|
116
|
+
name[0] = name[0].downcase
|
117
|
+
name
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_property(property)
|
121
|
+
@properties[property.name] = property
|
122
|
+
end
|
123
|
+
|
124
|
+
def properties
|
125
|
+
@properties.values
|
126
|
+
end
|
127
|
+
|
128
|
+
def needs_init?
|
129
|
+
for property in properties do
|
130
|
+
if property.needs_init?
|
131
|
+
return true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Property
|
140
|
+
attr_reader :name
|
141
|
+
|
142
|
+
def initialize(name)
|
143
|
+
@name = name
|
144
|
+
end
|
145
|
+
|
146
|
+
def internal_type
|
147
|
+
type
|
148
|
+
end
|
149
|
+
|
150
|
+
def exposed_type
|
151
|
+
type
|
152
|
+
end
|
153
|
+
|
154
|
+
def internal_name
|
155
|
+
"_#{@name}"
|
156
|
+
end
|
157
|
+
|
158
|
+
def exposed_name
|
159
|
+
@name
|
160
|
+
end
|
161
|
+
|
162
|
+
def type
|
163
|
+
raise "Implement me, or override internal_type and external_type"
|
164
|
+
end
|
165
|
+
|
166
|
+
def needs_init?
|
167
|
+
false
|
168
|
+
end
|
169
|
+
|
170
|
+
def init_line
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def setter_signature
|
175
|
+
name = exposed_name.to_s
|
176
|
+
name[0] = name[0].upcase
|
177
|
+
"- (void)set#{name}:(#{exposed_type})#{exposed_name}"
|
178
|
+
end
|
179
|
+
|
180
|
+
def assignation_value
|
181
|
+
exposed_name
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class StringProperty < Property
|
186
|
+
def type
|
187
|
+
'NSString *'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class IntegerProperty < Property
|
192
|
+
def type
|
193
|
+
'NSInteger'
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class UrlProperty < Property
|
198
|
+
def type
|
199
|
+
'NSURL *'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class DateProperty < Property
|
204
|
+
def type
|
205
|
+
'NSDate *'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class SetProperty < Property
|
210
|
+
def internal_type
|
211
|
+
'NSMutableSet *'
|
212
|
+
end
|
213
|
+
|
214
|
+
def exposed_type
|
215
|
+
'NSSet *'
|
216
|
+
end
|
217
|
+
|
218
|
+
def needs_init?
|
219
|
+
true
|
220
|
+
end
|
221
|
+
|
222
|
+
def init_line
|
223
|
+
"#{internal_name} = [[NSMutableSet alloc] init]"
|
224
|
+
end
|
225
|
+
|
226
|
+
def assignation_value
|
227
|
+
"[[NSMutableSet alloc] initWithSet:#{exposed_name}]"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class ArrayProperty < Property
|
232
|
+
def internal_type
|
233
|
+
'NSMutableArray *'
|
234
|
+
end
|
235
|
+
|
236
|
+
def exposed_type
|
237
|
+
'NSArray *'
|
238
|
+
end
|
239
|
+
|
240
|
+
def needs_init?
|
241
|
+
true
|
242
|
+
end
|
243
|
+
|
244
|
+
def init_line
|
245
|
+
"#{internal_name} = [[NSMutableArray alloc] init]";
|
246
|
+
end
|
247
|
+
|
248
|
+
def assignation_value
|
249
|
+
"[[NSMutableArray alloc] initWithArray:#{exposed_name}]"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class DefaultRunner
|
254
|
+
attr_accessor :pathname
|
255
|
+
|
256
|
+
def initialize
|
257
|
+
@pathname = 'Model' # Look for a file 'Model' in this directory
|
258
|
+
end
|
259
|
+
|
260
|
+
def run
|
261
|
+
if not File.exists?(@pathname)
|
262
|
+
raise 'No "Model" file found in the current directory'
|
263
|
+
end
|
264
|
+
|
265
|
+
project = Project.new()
|
266
|
+
source = File.new(@pathname).read()
|
267
|
+
|
268
|
+
builder = ProjectBuilder.new(project)
|
269
|
+
builder.instance_eval(source, @pathname, 1)
|
270
|
+
|
271
|
+
generator = Source::Generator.new(project)
|
272
|
+
generator.generate()
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
module Source
|
277
|
+
class Generator
|
278
|
+
def initialize(project)
|
279
|
+
@project = project
|
280
|
+
end
|
281
|
+
|
282
|
+
def generate(target_directory='.')
|
283
|
+
for cls in renderers do
|
284
|
+
renderer = cls.new()
|
285
|
+
|
286
|
+
for entity in @project.entities
|
287
|
+
vars = TemplateVars.new()
|
288
|
+
vars.project = @project
|
289
|
+
vars.entity = entity
|
290
|
+
|
291
|
+
filename = renderer.generated_file(vars)
|
292
|
+
fullpath = File.join(target_directory, filename)
|
293
|
+
fhandle = File.new(fullpath, 'w')
|
294
|
+
fhandle.write(renderer.result(vars))
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def renderers
|
300
|
+
[
|
301
|
+
HeaderRenderer,
|
302
|
+
ImplementationRenderer,
|
303
|
+
BuilderHeaderRenderer,
|
304
|
+
BuilderImplementationRenderer
|
305
|
+
]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class TemplateVars
|
310
|
+
attr_accessor :entity, :project, :file
|
311
|
+
|
312
|
+
def get_binding
|
313
|
+
binding
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class BaseRenderer
|
318
|
+
def template_file
|
319
|
+
raise 'Implement me'
|
320
|
+
end
|
321
|
+
|
322
|
+
def generated_file(template_vars)
|
323
|
+
raise 'Implement me'
|
324
|
+
end
|
325
|
+
|
326
|
+
def result(template_vars)
|
327
|
+
renderer.result(template_vars.get_binding)
|
328
|
+
end
|
329
|
+
|
330
|
+
def renderer
|
331
|
+
if not @renderer
|
332
|
+
mydir = File.dirname(__FILE__)
|
333
|
+
template_path = File.join(mydir, '../templates', template_file)
|
334
|
+
template = File.new(template_path).read()
|
335
|
+
@renderer = ERB.new(template, 0, '>')
|
336
|
+
end
|
337
|
+
|
338
|
+
@renderer
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
class HeaderRenderer < BaseRenderer
|
343
|
+
def template_file
|
344
|
+
'header.erb'
|
345
|
+
end
|
346
|
+
|
347
|
+
def generated_file(template_vars)
|
348
|
+
"#{template_vars.entity.name}.h"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
class ImplementationRenderer < BaseRenderer
|
353
|
+
def template_file
|
354
|
+
'implementation.erb'
|
355
|
+
end
|
356
|
+
|
357
|
+
def generated_file(template_vars)
|
358
|
+
"#{template_vars.entity.name}.m"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
class BuilderHeaderRenderer < BaseRenderer
|
363
|
+
def template_file
|
364
|
+
'builder_header.erb'
|
365
|
+
end
|
366
|
+
|
367
|
+
def generated_file(template_vars)
|
368
|
+
"#{template_vars.entity.name}Builder.h"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class BuilderImplementationRenderer < BaseRenderer
|
373
|
+
def template_file
|
374
|
+
'builder_implementation.erb'
|
375
|
+
end
|
376
|
+
|
377
|
+
def generated_file(template_vars)
|
378
|
+
"#{template_vars.entity.name}Builder.m"
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
class FileInfo
|
383
|
+
attr_accessor :pathname
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
//
|
2
|
+
// <%= entity.name %>Builder.h
|
3
|
+
// <%= project.name %>
|
4
|
+
|
5
|
+
<% if project.copyright %>
|
6
|
+
//
|
7
|
+
// Copyright (c) <%= project.copyright %>. All rights reserved.
|
8
|
+
<% end %>
|
9
|
+
//
|
10
|
+
// Generated by ModelMaker
|
11
|
+
// See http://github.com/aspyct/ModelMaker
|
12
|
+
//
|
13
|
+
|
14
|
+
#import <Foundation/Foundation.h>
|
15
|
+
#import "<%= entity.name %>.h"
|
16
|
+
|
17
|
+
@interface <%= entity.name %>Builder : NSObject
|
18
|
+
|
19
|
+
@property (readonly) <%= entity.name %> *<%= entity.instance_name %>;
|
20
|
+
|
21
|
+
- (id)init;
|
22
|
+
|
23
|
+
<% for property in entity.properties %>
|
24
|
+
<%= property.setter_signature %>;
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
@end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
//
|
2
|
+
// <%= entity.name %>Builder.m
|
3
|
+
// <%= project.name %>
|
4
|
+
|
5
|
+
<% if project.copyright %>
|
6
|
+
//
|
7
|
+
// Copyright (c) <%= project.copyright %>. All rights reserved.
|
8
|
+
<% end %>
|
9
|
+
//
|
10
|
+
// Generated by ModelMaker
|
11
|
+
// See http://github.com/aspyct/ModelMaker
|
12
|
+
//
|
13
|
+
|
14
|
+
#import "<%= entity.name %>Builder.h"
|
15
|
+
|
16
|
+
@implementation <%= entity.name %>Builder
|
17
|
+
|
18
|
+
@synthesize <%= entity.instance_name %> = _<%= entity.instance_name %>;
|
19
|
+
|
20
|
+
- (id)init {
|
21
|
+
self = [super init];
|
22
|
+
|
23
|
+
if (self) {
|
24
|
+
_<%= entity.instance_name %> = [[<%= entity.name %> alloc] init];
|
25
|
+
}
|
26
|
+
|
27
|
+
return self;
|
28
|
+
}
|
29
|
+
|
30
|
+
<% for property in entity.properties %>
|
31
|
+
<%= property.setter_signature %> {
|
32
|
+
_<%= entity.instance_name %>-><%= property.internal_name %> = <%= property.assignation_value %>;
|
33
|
+
}
|
34
|
+
|
35
|
+
<% end %>
|
36
|
+
@end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
//
|
2
|
+
// <%= entity.name %>.h
|
3
|
+
// <%= project.name %>
|
4
|
+
|
5
|
+
<% if project.copyright %>
|
6
|
+
//
|
7
|
+
// Copyright (c) <%= project.copyright %>. All rights reserved.
|
8
|
+
<% end %>
|
9
|
+
//
|
10
|
+
// Generated by ModelMaker
|
11
|
+
// See http://github.com/aspyct/ModelMaker
|
12
|
+
//
|
13
|
+
|
14
|
+
#import <Foundation/Foundation.h>
|
15
|
+
|
16
|
+
@interface <%= @entity.name %> : <%= @entity.superclass %> <%= '<' + @entity.protocols.join(', ') + '> ' if not @entity.protocols.empty? %>{
|
17
|
+
@package
|
18
|
+
<% for @property in @entity.properties %>
|
19
|
+
<%= @property.internal_type %> <%= @property.internal_name %>;
|
20
|
+
<% end %>
|
21
|
+
}
|
22
|
+
|
23
|
+
<% for @property in @entity.properties %>
|
24
|
+
@property (readonly) <%= @property.exposed_type %> <%= @property.exposed_name %>;
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
@end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
//
|
2
|
+
// <%= entity.name %>.m
|
3
|
+
// <%= project.name %>
|
4
|
+
|
5
|
+
<% if project.copyright %>
|
6
|
+
//
|
7
|
+
// Copyright (c) <%= project.copyright %>. All rights reserved.
|
8
|
+
<% end %>
|
9
|
+
//
|
10
|
+
// Generated by ModelMaker
|
11
|
+
// See http://github.com/aspyct/ModelMaker
|
12
|
+
//
|
13
|
+
|
14
|
+
#import "<%= @entity.name %>.h"
|
15
|
+
|
16
|
+
@implementation <%= @entity.name %>
|
17
|
+
|
18
|
+
|
19
|
+
<% for @property in @entity.properties %>
|
20
|
+
@synthesize <%= @property.exposed_name %> = <%= @property.internal_name %>;
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<% if @entity.needs_init? %>
|
24
|
+
- (id)init
|
25
|
+
{
|
26
|
+
self = [super init];
|
27
|
+
|
28
|
+
if (self) {
|
29
|
+
<% for @property in @entity.properties %><% if @property.needs_init? %>
|
30
|
+
<%= @property.init_line %>;
|
31
|
+
<% end %><% end %>
|
32
|
+
}
|
33
|
+
|
34
|
+
return self;
|
35
|
+
}
|
36
|
+
|
37
|
+
<% end %>
|
38
|
+
@end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: modelmaker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Antoine d'Otreppe
|
9
|
+
autorequire:
|
10
|
+
bindir: src/bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-16 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'ModelMaker generates your model classes based on a simple ruby definition. '
|
15
|
+
email: a.dotreppe@aspyct.org
|
16
|
+
executables:
|
17
|
+
- modelmake
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- src/templates/builder_header.erb
|
22
|
+
- src/templates/builder_implementation.erb
|
23
|
+
- src/templates/header.erb
|
24
|
+
- src/templates/implementation.erb
|
25
|
+
- src/bin/modelmake
|
26
|
+
- src/lib/modelmaker.rb
|
27
|
+
homepage: https://github.com/aspyct/ModelMaker
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- src/lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.24
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: Objective-C model class generator
|
52
|
+
test_files: []
|
53
|
+
has_rdoc:
|