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.
Files changed (52) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +11 -0
  3. data/Rakefile +76 -0
  4. data/VERSION +1 -0
  5. data/bin/xdry +4 -0
  6. data/lib/xdry.rb +18 -0
  7. data/lib/xdry/boxing.rb +212 -0
  8. data/lib/xdry/generators/ctor_from_field.rb +91 -0
  9. data/lib/xdry/generators/dealloc.rb +53 -0
  10. data/lib/xdry/generators/dictionary_coding.rb +129 -0
  11. data/lib/xdry/generators/field_from_property.rb +20 -0
  12. data/lib/xdry/generators/property-from-field.rb +22 -0
  13. data/lib/xdry/generators/storing_constructor.rb +72 -0
  14. data/lib/xdry/generators/synthesize.rb +25 -0
  15. data/lib/xdry/generators_support.rb +42 -0
  16. data/lib/xdry/parsing/driver.rb +106 -0
  17. data/lib/xdry/parsing/model.rb +272 -0
  18. data/lib/xdry/parsing/nodes.rb +260 -0
  19. data/lib/xdry/parsing/parsers.rb +166 -0
  20. data/lib/xdry/parsing/parts/selectors.rb +95 -0
  21. data/lib/xdry/parsing/parts/var_types.rb +66 -0
  22. data/lib/xdry/parsing/pos.rb +75 -0
  23. data/lib/xdry/parsing/scope_stack.rb +68 -0
  24. data/lib/xdry/parsing/scopes.rb +61 -0
  25. data/lib/xdry/parsing/scopes_support.rb +143 -0
  26. data/lib/xdry/patching/emitter.rb +60 -0
  27. data/lib/xdry/patching/insertion_points.rb +209 -0
  28. data/lib/xdry/patching/item_patchers.rb +74 -0
  29. data/lib/xdry/patching/patcher.rb +139 -0
  30. data/lib/xdry/run.rb +227 -0
  31. data/lib/xdry/support/enumerable_additions.rb +35 -0
  32. data/lib/xdry/support/string_additions.rb +27 -0
  33. data/lib/xdry/support/symbol_additions.rb +14 -0
  34. data/site/_config.yml +3 -0
  35. data/site/_example +9 -0
  36. data/site/_layouts/default.html +30 -0
  37. data/site/_plugins/example.rb +16 -0
  38. data/site/_plugins/highlight_unindent.rb +17 -0
  39. data/site/index.md +417 -0
  40. data/site/master.css +94 -0
  41. data/spec/boxing_spec.rb +80 -0
  42. data/spec/ctor_from_field_spec.rb +251 -0
  43. data/spec/dealloc_spec.rb +103 -0
  44. data/spec/dictionary_coding_spec.rb +132 -0
  45. data/spec/field_from_prop_spec.rb +72 -0
  46. data/spec/prop_from_field_spec.rb +39 -0
  47. data/spec/readme_samples_spec.rb +76 -0
  48. data/spec/spec.opts +3 -0
  49. data/spec/spec_helper.rb +53 -0
  50. data/spec/synthesize_spec.rb +94 -0
  51. data/xdry.gemspec +103 -0
  52. 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
@@ -0,0 +1,14 @@
1
+
2
+ module XDry
3
+
4
+ module SymbolAdditions
5
+
6
+ def to_proc
7
+ proc { |obj, *args| obj.send(self, *args) }
8
+ end
9
+
10
+ end
11
+
12
+ Symbol.send(:include, SymbolAdditions)
13
+
14
+ end
data/site/_config.yml ADDED
@@ -0,0 +1,3 @@
1
+ safe: false
2
+ lsi: false
3
+ pygments: true
data/site/_example ADDED
@@ -0,0 +1,9 @@
1
+ {% example %}
2
+
3
+ {% highlight objc %}
4
+ {% endhighlight %}
5
+
6
+ {% highlight objc %}
7
+ {% endhighlight %}
8
+
9
+ {% endexample %}
@@ -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.