xdry 0.1.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.
- data/LICENSE +20 -0
- data/README.md +11 -0
- data/Rakefile +76 -0
- data/VERSION +1 -0
- data/bin/xdry +4 -0
- data/lib/xdry.rb +18 -0
- data/lib/xdry/boxing.rb +212 -0
- data/lib/xdry/generators/ctor_from_field.rb +91 -0
- data/lib/xdry/generators/dealloc.rb +53 -0
- data/lib/xdry/generators/dictionary_coding.rb +129 -0
- data/lib/xdry/generators/field_from_property.rb +20 -0
- data/lib/xdry/generators/property-from-field.rb +22 -0
- data/lib/xdry/generators/storing_constructor.rb +72 -0
- data/lib/xdry/generators/synthesize.rb +25 -0
- data/lib/xdry/generators_support.rb +42 -0
- data/lib/xdry/parsing/driver.rb +106 -0
- data/lib/xdry/parsing/model.rb +272 -0
- data/lib/xdry/parsing/nodes.rb +260 -0
- data/lib/xdry/parsing/parsers.rb +166 -0
- data/lib/xdry/parsing/parts/selectors.rb +95 -0
- data/lib/xdry/parsing/parts/var_types.rb +66 -0
- data/lib/xdry/parsing/pos.rb +75 -0
- data/lib/xdry/parsing/scope_stack.rb +68 -0
- data/lib/xdry/parsing/scopes.rb +61 -0
- data/lib/xdry/parsing/scopes_support.rb +143 -0
- data/lib/xdry/patching/emitter.rb +60 -0
- data/lib/xdry/patching/insertion_points.rb +209 -0
- data/lib/xdry/patching/item_patchers.rb +74 -0
- data/lib/xdry/patching/patcher.rb +139 -0
- data/lib/xdry/run.rb +227 -0
- data/lib/xdry/support/enumerable_additions.rb +35 -0
- data/lib/xdry/support/string_additions.rb +27 -0
- data/lib/xdry/support/symbol_additions.rb +14 -0
- data/site/_config.yml +3 -0
- data/site/_example +9 -0
- data/site/_layouts/default.html +30 -0
- data/site/_plugins/example.rb +16 -0
- data/site/_plugins/highlight_unindent.rb +17 -0
- data/site/index.md +417 -0
- data/site/master.css +94 -0
- data/spec/boxing_spec.rb +80 -0
- data/spec/ctor_from_field_spec.rb +251 -0
- data/spec/dealloc_spec.rb +103 -0
- data/spec/dictionary_coding_spec.rb +132 -0
- data/spec/field_from_prop_spec.rb +72 -0
- data/spec/prop_from_field_spec.rb +39 -0
- data/spec/readme_samples_spec.rb +76 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/synthesize_spec.rb +94 -0
- data/xdry.gemspec +103 -0
- metadata +141 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
module EnumerableAdditions
|
5
|
+
|
6
|
+
def prefix_while
|
7
|
+
result = []
|
8
|
+
each do |item|
|
9
|
+
if yield(item)
|
10
|
+
result << item
|
11
|
+
else
|
12
|
+
break
|
13
|
+
end
|
14
|
+
end
|
15
|
+
return result
|
16
|
+
end
|
17
|
+
|
18
|
+
def suffix_while
|
19
|
+
result = []
|
20
|
+
reverse_each do |item|
|
21
|
+
if yield(item)
|
22
|
+
result << item
|
23
|
+
else
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return result.reverse!
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# tried to extend Enumerable here, but it did not work, so resorted to only extending Array
|
33
|
+
Array.send(:include, EnumerableAdditions)
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
module StringAdditions
|
5
|
+
|
6
|
+
def blank?
|
7
|
+
self =~ /^\s*$/
|
8
|
+
end
|
9
|
+
|
10
|
+
def capitalized_identifier
|
11
|
+
case self
|
12
|
+
when 'id', 'uid' then upcase
|
13
|
+
else self[0..0].upcase + self[1..-1]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def prefixed_as_arg_name
|
18
|
+
prefix = case self when /^[aeiou]/ then 'an' else 'a' end
|
19
|
+
|
20
|
+
prefix + self.capitalized_identifier
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
String.send(:include, StringAdditions)
|
26
|
+
|
27
|
+
end
|
data/site/_config.yml
ADDED
data/site/_example
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Objective-C boilerplate generator — Extra DRY</title>
|
6
|
+
<link href='http://fonts.googleapis.com/css?family=Pacifico' rel='stylesheet' type='text/css'>
|
7
|
+
<link href='http://fonts.googleapis.com/css?family=PT+Serif' rel='stylesheet' type='text/css'>
|
8
|
+
<link href="master.css" rel="stylesheet" type="text/css" media="screen" charset="utf-8">
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
<a href="http://github.com/andreyvit/xdry"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
|
13
|
+
|
14
|
+
<div id="container">
|
15
|
+
|
16
|
+
{{ content }}
|
17
|
+
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<script type="text/javascript">
|
21
|
+
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
22
|
+
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
23
|
+
</script>
|
24
|
+
<script type="text/javascript">
|
25
|
+
try {
|
26
|
+
var pageTracker = _gat._getTracker("UA-861679-14");
|
27
|
+
pageTracker._trackPageview();
|
28
|
+
} catch(err) {}</script>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Jekyll
|
3
|
+
class HelloTag < Liquid::Block
|
4
|
+
|
5
|
+
def initialize(tag_name, text, tokens)
|
6
|
+
super
|
7
|
+
@text = text
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(context)
|
11
|
+
['<div class="example">'] + super + ['</div>']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Liquid::Template.register_tag('example', Jekyll::HelloTag)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Jekyll::HighlightBlock
|
2
|
+
|
3
|
+
def render_pygments_with_unindent(context, code)
|
4
|
+
code = code.split("\n").collect do |line|
|
5
|
+
if line =~ /^ {4}/
|
6
|
+
line[4..-1]
|
7
|
+
else
|
8
|
+
line
|
9
|
+
end
|
10
|
+
end.join("\n")
|
11
|
+
render_pygments_without_unindent(context, code)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :render_pygments_without_unindent, :render_pygments
|
15
|
+
alias_method :render_pygments, :render_pygments_with_unindent
|
16
|
+
|
17
|
+
end
|
data/site/index.md
ADDED
@@ -0,0 +1,417 @@
|
|
1
|
+
---
|
2
|
+
title: Home
|
3
|
+
layout: default
|
4
|
+
---
|
5
|
+
|
6
|
+
Objective-C boilerplate generator
|
7
|
+
=================================
|
8
|
+
|
9
|
+
Run Extra D.R.Y. in your Objective-C project folder to automatically add (upon your request):
|
10
|
+
|
11
|
+
* `@property`, `@synthesize`, field declarations,
|
12
|
+
* initializing constructors,
|
13
|
+
* missing release calls in dealloc,
|
14
|
+
* initWithDictionary, dictionaryRepresentation based on the chosen fields.
|
15
|
+
|
16
|
+
|
17
|
+
Installation
|
18
|
+
------------
|
19
|
+
|
20
|
+
Install the command-line utility via RubyGems:
|
21
|
+
|
22
|
+
sudo gem install xdry
|
23
|
+
|
24
|
+
|
25
|
+
Basic Usage
|
26
|
+
-----------
|
27
|
+
|
28
|
+
Tell XD.R.Y. which changes you want done using bang-commands. For example,
|
29
|
+
add `!p` to a field declaration line to generate a property:
|
30
|
+
|
31
|
+
{% example %}
|
32
|
+
|
33
|
+
{% highlight objc %}
|
34
|
+
// Foo.h
|
35
|
+
@interface Foo {
|
36
|
+
Bar *value; !p
|
37
|
+
}
|
38
|
+
|
39
|
+
@end
|
40
|
+
|
41
|
+
// Foo.m
|
42
|
+
@implementation Foo
|
43
|
+
@end
|
44
|
+
{% endhighlight %}
|
45
|
+
|
46
|
+
{% highlight objc %}
|
47
|
+
// Foo.h
|
48
|
+
@interface Foo {
|
49
|
+
Bar *value;
|
50
|
+
}
|
51
|
+
|
52
|
+
@property(nonatomic, retain) Bar *value;
|
53
|
+
|
54
|
+
@end
|
55
|
+
|
56
|
+
// Foo.m
|
57
|
+
@implementation Foo
|
58
|
+
|
59
|
+
@synthesize value;
|
60
|
+
|
61
|
+
- (void)dealloc {
|
62
|
+
[value release], value = nil;
|
63
|
+
[super dealloc];
|
64
|
+
}
|
65
|
+
|
66
|
+
@end
|
67
|
+
{% endhighlight %}
|
68
|
+
|
69
|
+
{% endexample %}
|
70
|
+
|
71
|
+
To run XD.R.Y., open a Terminal, cd to your project folder and execute `xdry`:
|
72
|
+
|
73
|
+
cd ~/Documents/HelloWorld
|
74
|
+
xdry
|
75
|
+
|
76
|
+
|
77
|
+
Automatic Changes
|
78
|
+
-----------------
|
79
|
+
|
80
|
+
Without any instructions from your side, XD.R.Y. automatically applies the following
|
81
|
+
changes:
|
82
|
+
|
83
|
+
* Adds missing release calls to `dealloc` methods:
|
84
|
+
|
85
|
+
{% example %}
|
86
|
+
|
87
|
+
{% highlight objc %}
|
88
|
+
@interface Foo {
|
89
|
+
NSString *value;
|
90
|
+
}
|
91
|
+
@end
|
92
|
+
|
93
|
+
@implementation Foo
|
94
|
+
@end
|
95
|
+
{% endhighlight %}
|
96
|
+
|
97
|
+
{% highlight objc %}
|
98
|
+
@interface Foo {
|
99
|
+
NSString *value;
|
100
|
+
}
|
101
|
+
@end
|
102
|
+
|
103
|
+
@implementation Foo
|
104
|
+
|
105
|
+
- (void)dealloc {
|
106
|
+
[value release], value = nil;
|
107
|
+
[super dealloc];
|
108
|
+
}
|
109
|
+
|
110
|
+
@end
|
111
|
+
{% endhighlight %}
|
112
|
+
|
113
|
+
{% endexample %}
|
114
|
+
|
115
|
+
* Adds missing `@synthesize` declarations for properties with no explicit accessor methods:
|
116
|
+
|
117
|
+
{% example %}
|
118
|
+
|
119
|
+
{% highlight objc %}
|
120
|
+
@interface Foo {
|
121
|
+
NSString *value;
|
122
|
+
}
|
123
|
+
|
124
|
+
@property(nonatomic, copy) NSString *value;
|
125
|
+
|
126
|
+
@end
|
127
|
+
|
128
|
+
@implementation Foo
|
129
|
+
@end
|
130
|
+
{% endhighlight %}
|
131
|
+
|
132
|
+
{% highlight objc %}
|
133
|
+
@interface Foo {
|
134
|
+
NSString *value;
|
135
|
+
}
|
136
|
+
|
137
|
+
@property(nonatomic, copy) NSString *value;
|
138
|
+
|
139
|
+
@end
|
140
|
+
|
141
|
+
@implementation Foo
|
142
|
+
|
143
|
+
@synthesize value;
|
144
|
+
|
145
|
+
@end
|
146
|
+
{% endhighlight %}
|
147
|
+
|
148
|
+
{% endexample %}
|
149
|
+
|
150
|
+
* Adds missing fields for declared properties:
|
151
|
+
|
152
|
+
{% example %}
|
153
|
+
|
154
|
+
{% highlight objc %}
|
155
|
+
@interface Foo {
|
156
|
+
}
|
157
|
+
|
158
|
+
@property(nonatomic, copy) NSString *value;
|
159
|
+
|
160
|
+
@end
|
161
|
+
{% endhighlight %}
|
162
|
+
|
163
|
+
{% highlight objc %}
|
164
|
+
@interface Foo {
|
165
|
+
NSString *value;
|
166
|
+
}
|
167
|
+
|
168
|
+
@property(nonatomic, copy) NSString *value;
|
169
|
+
|
170
|
+
@end
|
171
|
+
{% endhighlight %}
|
172
|
+
|
173
|
+
{% endexample %}
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
Properties, Fields, Constructors
|
178
|
+
--------------------------------
|
179
|
+
|
180
|
+
`!p` — generate a property for the given field:
|
181
|
+
|
182
|
+
{% example %}
|
183
|
+
|
184
|
+
{% highlight objc %}
|
185
|
+
@interface Foo {
|
186
|
+
Bar *value; !p
|
187
|
+
}
|
188
|
+
|
189
|
+
@end
|
190
|
+
|
191
|
+
@implementation Foo
|
192
|
+
@end
|
193
|
+
{% endhighlight %}
|
194
|
+
|
195
|
+
{% highlight objc %}
|
196
|
+
@interface Foo {
|
197
|
+
Bar *value;
|
198
|
+
}
|
199
|
+
|
200
|
+
@property(nonatomic, retain) Bar *value;
|
201
|
+
|
202
|
+
@end
|
203
|
+
|
204
|
+
@implementation Foo
|
205
|
+
|
206
|
+
@synthesize value;
|
207
|
+
|
208
|
+
- (void)dealloc {
|
209
|
+
[value release], value = nil;
|
210
|
+
[super dealloc];
|
211
|
+
}
|
212
|
+
|
213
|
+
@end
|
214
|
+
{% endhighlight %}
|
215
|
+
|
216
|
+
{% endexample %}
|
217
|
+
|
218
|
+
|
219
|
+
|
220
|
+
`!c` — generate an initializing constructor for the given field(s):
|
221
|
+
|
222
|
+
{% example %}
|
223
|
+
|
224
|
+
{% highlight objc %}
|
225
|
+
@interface Foo {
|
226
|
+
NSString *_something; !c
|
227
|
+
}
|
228
|
+
@end
|
229
|
+
|
230
|
+
@implementation Foo
|
231
|
+
@end
|
232
|
+
{% endhighlight %}
|
233
|
+
|
234
|
+
{% highlight objc %}
|
235
|
+
@interface Foo {
|
236
|
+
NSString *_something;
|
237
|
+
}
|
238
|
+
|
239
|
+
- (id)initWithSomething:(NSString *)something;
|
240
|
+
|
241
|
+
@end
|
242
|
+
|
243
|
+
@implementation Foo
|
244
|
+
|
245
|
+
- (id)initWithSomething:(NSString *)something {
|
246
|
+
if (self = [super init]) {
|
247
|
+
_something = [something copy];
|
248
|
+
}
|
249
|
+
return self;
|
250
|
+
}
|
251
|
+
|
252
|
+
@end
|
253
|
+
{% endhighlight %}
|
254
|
+
|
255
|
+
{% endexample %}
|
256
|
+
|
257
|
+
|
258
|
+
Dictionary Coding
|
259
|
+
-----------------
|
260
|
+
|
261
|
+
XD.R.Y. can generate `initWithDictionary:(NSDictionary *)dictionary` method, useful for loading objects from a plist. Similarly, an `(NSDictionary *)dictionaryRepresentation` method is generated to produce a plist-friendly dictionary from an object.
|
262
|
+
|
263
|
+
`// persistent` marks a block of fields to read from a dictionary / serialize into a dictionary:
|
264
|
+
|
265
|
+
{% example %}
|
266
|
+
|
267
|
+
{% highlight objc %}
|
268
|
+
@interface Foo {
|
269
|
+
// persistent
|
270
|
+
NSString *_something;
|
271
|
+
}
|
272
|
+
@end
|
273
|
+
|
274
|
+
@implementation Foo
|
275
|
+
@end
|
276
|
+
{% endhighlight %}
|
277
|
+
|
278
|
+
{% highlight objc %}
|
279
|
+
@interface Foo {
|
280
|
+
// persistent
|
281
|
+
NSString *_something;
|
282
|
+
}
|
283
|
+
@end
|
284
|
+
|
285
|
+
#define SomethingKey @"Something"
|
286
|
+
|
287
|
+
@implementation Foo
|
288
|
+
|
289
|
+
- (id)initWithDictionary:(NSDictionary *)dictionary {
|
290
|
+
if (self = [super init]) {
|
291
|
+
id somethingRaw = [dictionary objectForKey:SomethingKey];
|
292
|
+
if (somethingRaw != nil) {
|
293
|
+
_something = [somethingRaw copy];
|
294
|
+
}
|
295
|
+
}
|
296
|
+
return self;
|
297
|
+
}
|
298
|
+
|
299
|
+
- (NSDictionary *)dictionaryRepresentation {
|
300
|
+
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
301
|
+
[dictionary setObject:_something forKey:SomethingKey];
|
302
|
+
return dictionary;
|
303
|
+
}
|
304
|
+
|
305
|
+
@end
|
306
|
+
{% endhighlight %}
|
307
|
+
|
308
|
+
{% endexample %}
|
309
|
+
|
310
|
+
To correctly handle serialization and deserialization of arrays,
|
311
|
+
you need to hint XD.R.Y. about the item type:
|
312
|
+
|
313
|
+
{% example %}
|
314
|
+
|
315
|
+
{% highlight objc %}
|
316
|
+
@interface Foo {
|
317
|
+
// persistent
|
318
|
+
NSArray *_bars; // of Bar
|
319
|
+
}
|
320
|
+
@end
|
321
|
+
|
322
|
+
@implementation Foo
|
323
|
+
@end
|
324
|
+
{% endhighlight %}
|
325
|
+
|
326
|
+
{% highlight objc %}
|
327
|
+
@interface Foo {
|
328
|
+
// persistent
|
329
|
+
NSArray *_bars; // of Bar
|
330
|
+
}
|
331
|
+
@end
|
332
|
+
|
333
|
+
@implementation Foo
|
334
|
+
#define BarsKey @"Bars"
|
335
|
+
|
336
|
+
@implementation Foo
|
337
|
+
|
338
|
+
- (id)initWithDictionary:(NSDictionary *)dictionary {
|
339
|
+
if (self = [super init]) {
|
340
|
+
id barsRaw = [dictionary objectForKey:BarsKey];
|
341
|
+
if (barsRaw != nil) {
|
342
|
+
NSMutableArray *barsArray = [[NSMutableArray alloc] init];
|
343
|
+
for (NSDictionary *barsItemDict in (NSArray *) barsRaw) {
|
344
|
+
Bar *barsItem = [[Bar alloc] initWithDictionary:barsItemDict];
|
345
|
+
[barsArray addObject:barsItem];
|
346
|
+
[barsItem release];
|
347
|
+
}
|
348
|
+
_bars = barsArray;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
return self;
|
352
|
+
}
|
353
|
+
|
354
|
+
- (NSDictionary *)dictionaryRepresentation {
|
355
|
+
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
356
|
+
NSMutableArray *barsArray = [NSMutableArray array];
|
357
|
+
for (Bar *barsItem in _bars) {
|
358
|
+
[barsArray addObject:[barsItem dictionaryRepresentation]];
|
359
|
+
}
|
360
|
+
[dictionary setObject:barsArray forKey:BarsKey];
|
361
|
+
return dictionary;
|
362
|
+
}
|
363
|
+
|
364
|
+
- (void)dealloc {
|
365
|
+
[_bars release], _bars = nil;
|
366
|
+
[super dealloc];
|
367
|
+
}
|
368
|
+
|
369
|
+
@end
|
370
|
+
{% endhighlight %}
|
371
|
+
|
372
|
+
{% endexample %}
|
373
|
+
|
374
|
+
|
375
|
+
|
376
|
+
License and Authors
|
377
|
+
-------------------
|
378
|
+
|
379
|
+
Copyright 2010–2011, Andrey Tarantsov.
|
380
|
+
|
381
|
+
Distributed under the MIT license, see LICENSE file for details.
|
382
|
+
|
383
|
+
|
384
|
+
Contributing
|
385
|
+
------------
|
386
|
+
|
387
|
+
Fork the source on GitHub: [http://github.com/andreyvit/xdry](http://github.com/andreyvit/xdry).
|
388
|
+
|
389
|
+
Add a test, make a change, verify that all tests pass, update the docs in site/index.md, send me a pull request.
|
390
|
+
|
391
|
+
Testing prerequisites:
|
392
|
+
|
393
|
+
sudo gem install rake rspec diff-lcs
|
394
|
+
|
395
|
+
The simplest way to run the tests:
|
396
|
+
|
397
|
+
rake
|
398
|
+
|
399
|
+
Get a nice colorful table with test results:
|
400
|
+
|
401
|
+
rspec -b -c -fd .
|
402
|
+
|
403
|
+
When something goes wrong, you want a verbose output:
|
404
|
+
|
405
|
+
VERBOSE=1 rake
|
406
|
+
|
407
|
+
Site (documentation) prerequisites:
|
408
|
+
|
409
|
+
sudo gem install jekyll
|
410
|
+
sudo easy_install Pygments
|
411
|
+
|
412
|
+
Regenerate the site using:
|
413
|
+
|
414
|
+
rake site:build
|
415
|
+
|
416
|
+
(open site/_site/index.html to view the results).
|
417
|
+
Don't bother with gh-pages branch.
|