xdry 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,260 @@
1
+
2
+ module XDry
3
+
4
+ class Node
5
+ attr_accessor :pos, :indent
6
+
7
+ def initialize
8
+ @tags = Set.new
9
+ end
10
+
11
+ def tags
12
+ @tags.dup
13
+ end
14
+
15
+ def tags= new_tags
16
+ @tags = Set.new(new_tags)
17
+ end
18
+
19
+ def tagged_with? tag
20
+ @tags.include? tag
21
+ end
22
+
23
+ def tags_comment
24
+ if @tags.empty? then "" else " // " + @tags.to_a.sort.join(", ") end
25
+ end
26
+
27
+ def method_missing id, *args, &block
28
+ if id.to_s =~ /^with_(.*)$/
29
+ send("#{$1}=", *args, &block)
30
+ self
31
+ else
32
+ super(id, *args, &block)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ class NInterfaceFieldsEnd < Node
39
+ end
40
+
41
+ class NFieldDef < Node
42
+ attr_reader :name, :type
43
+
44
+ def initialize name, type
45
+ super()
46
+ @name, @type = name, type
47
+ end
48
+
49
+ def persistent?
50
+ tagged_with? 'persistent'
51
+ end
52
+
53
+ def wants_property?
54
+ tagged_with? 'wants-property'
55
+ end
56
+
57
+ def wants_constructor?
58
+ tagged_with? 'wants-constructor'
59
+ end
60
+
61
+ def to_s
62
+ "#{@type} #{@name}#{tags_comment}"
63
+ end
64
+
65
+ def to_source
66
+ "#{@type.to_source_with_space}#{@name};"
67
+ end
68
+ end
69
+
70
+ class NPropertyDef < Node
71
+ attr_reader :name, :type
72
+
73
+ def initialize name, type
74
+ super()
75
+ raise StandardError, "type cannot be nil for prop #{name}" if type.nil?
76
+ @name, @type = name, type
77
+ end
78
+
79
+ def outlet?
80
+ tagged_with? 'outlet'
81
+ end
82
+
83
+ def to_s
84
+ "#{if outlet? then 'IBOutlet ' else '' end}#{@type} #{@name}"
85
+ end
86
+
87
+ def to_source
88
+ retainment = case @type.default_property_retainment_policy
89
+ when '' then ''
90
+ else ', ' + @type.default_property_retainment_policy
91
+ end
92
+ iboutlet = if outlet? then "IBOutlet " else '' end
93
+ "@property(nonatomic#{retainment}) #{iboutlet}#{@type.to_source_with_space}#{@name};"
94
+ end
95
+ end
96
+
97
+ class NMethodHeader < Node
98
+ attr_reader :selector_def, :ret_type
99
+
100
+ def initialize selector_def, ret_type
101
+ @selector_def, @ret_type = selector_def, ret_type
102
+ end
103
+
104
+ def selector
105
+ @selector_def.selector
106
+ end
107
+
108
+ def to_s
109
+ "- (#{@ret_type})#{selector_def}"
110
+ end
111
+
112
+ end
113
+
114
+ class NMethodStart < Node
115
+ attr_reader :selector_def, :ret_type
116
+
117
+ def initialize selector_def, ret_type
118
+ @selector_def, @ret_type = selector_def, ret_type
119
+ end
120
+
121
+ def selector
122
+ @selector_def.selector
123
+ end
124
+
125
+ def to_s
126
+ "- (#{@ret_type})#{selector_def}"
127
+ end
128
+
129
+ end
130
+
131
+ class NInterfaceStart < Node
132
+ attr_reader :class_name
133
+ def initialize class_name
134
+ @class_name = class_name
135
+ end
136
+ end
137
+
138
+ class NImplementationStart < Node
139
+ attr_reader :class_name
140
+ def initialize class_name
141
+ @class_name = class_name
142
+ end
143
+ end
144
+
145
+ class NEnd < Node
146
+ end
147
+
148
+ class SynthesizeItem
149
+
150
+ attr_reader :property_name, :field_name
151
+
152
+ def initialize property_name, field_name = nil
153
+ @property_name, @field_name = property_name, field_name
154
+ end
155
+
156
+ def has_field_name?
157
+ not @field_name.nil?
158
+ end
159
+
160
+ def to_s
161
+ if has_field_name?
162
+ "#{property_name}=#{field_name}"
163
+ else
164
+ "#{property_name}"
165
+ end
166
+ end
167
+
168
+ def self.parse string
169
+ case string
170
+ when /^(\w+)$/ then SynthesizeItem.new($1, nil)
171
+ when /^(\w+)\s*=\s*(\w+)$/ then SynthesizeItem.new($1, $2)
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+ class NSynthesize < Node
178
+
179
+ attr_reader :items
180
+
181
+ def initialize items
182
+ @items = items
183
+ end
184
+
185
+ def item_for_property_named property_name
186
+ @items.find { |item| item.property_name == property_name }
187
+ end
188
+
189
+ def to_s
190
+ "@synthesize " + @items.join(", ") + ";"
191
+ end
192
+
193
+ def self.parse string
194
+ if string =~ /^@synthesize\s+(.*);$/
195
+ NSynthesize.new($1.strip.split(/\s+,\s+/).collect { |s| SynthesizeItem.parse(s) }.compact)
196
+ end
197
+ end
198
+
199
+ end
200
+
201
+ class NOpeningBrace < Node
202
+ end
203
+
204
+ class NClosingBrace < Node
205
+ end
206
+
207
+ class NMethodEnd < Node
208
+ end
209
+
210
+ class NReleaseCall < Node
211
+ attr_reader :expr
212
+
213
+ def initialize expr
214
+ @expr = expr
215
+ end
216
+ end
217
+
218
+ class NSuperCall < Node
219
+ end
220
+
221
+ class NReturn < Node
222
+ end
223
+
224
+ class NDefine < Node
225
+ attr_reader :word
226
+
227
+ def initialize word
228
+ @word = word
229
+ end
230
+ end
231
+
232
+ class NLine < Node
233
+
234
+ attr_reader :line
235
+
236
+ def initialize line
237
+ @line = line
238
+ end
239
+
240
+ end
241
+
242
+ class NMarker < Node
243
+ attr_reader :text
244
+
245
+ def initialize text
246
+ @text = text
247
+ end
248
+
249
+ def to_s
250
+ "#{self.class.name}('#{text}')"
251
+ end
252
+ end
253
+
254
+ class NPartLineMarker < NMarker
255
+ end
256
+
257
+ class NFullLineMarker < NMarker
258
+ end
259
+
260
+ end
@@ -0,0 +1,166 @@
1
+ require 'set'
2
+
3
+ module XDry
4
+
5
+ class Parser
6
+
7
+ attr_reader :scope
8
+
9
+ def initialize scope
10
+ @scope = scope
11
+ end
12
+
13
+ def to_s
14
+ "#{self.class.name}"
15
+ end
16
+
17
+ end
18
+
19
+ class PGlobal < Parser
20
+
21
+ def parse_line! line, eol_comments, indent
22
+ case line
23
+ when /^@interface\s+(\w+)\s*;/
24
+ name = $1
25
+ when /^@protocol\s+(\w+)\s*;/
26
+ name = $1
27
+
28
+ when /^@interface\s+(\w+)/ #\s*(?:[:(][\w:(),\s]*)?
29
+ name, supers, postfix = $1, $2, $'
30
+ yield NInterfaceStart.new(name)
31
+ yield NOpeningBrace.new if postfix =~ /\{$/
32
+
33
+ when /^@implementation\s+(\w+)/
34
+ name = $1
35
+ yield NImplementationStart.new(name)
36
+
37
+ when /^@protocol\s+(\w+)\s*;/
38
+ puts "PREDEF protocol #{$1}"
39
+
40
+ when /^#define\s+(\w+)/
41
+ word = $1
42
+ yield NDefine.new(word)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ class PInterfaceFields < Parser
49
+
50
+ def initialize scope
51
+ super
52
+ @tags = Set.new
53
+ end
54
+
55
+ def parse_line! line, eol_comments, indent
56
+ @this_line_tags = Set.new
57
+ [[/!p\b/, 'wants-property'], [/!c\b/, 'wants-constructor']].each do |regexp, tag|
58
+ if line =~ regexp
59
+ marker = $&
60
+ is_full_line = line.gsub(marker, '').strip.empty?
61
+ klass = is_full_line ? NFullLineMarker : NPartLineMarker
62
+ yield klass.new(marker)
63
+ (is_full_line ? @tags : @this_line_tags) << tag
64
+ return if is_full_line
65
+ end
66
+ end
67
+ case line
68
+ when /\}/
69
+ yield NInterfaceFieldsEnd.new
70
+ when %r~^//\s*persistent$~
71
+ @tags << 'persistent'
72
+ when ''
73
+ @tags.clear
74
+ when /^(\w+)\s+(\w+)\s*;/
75
+ type_name, field_name = $1, $2
76
+ yield process_type_hint(NFieldDef.new(field_name, SimpleVarType.new(type_name)), eol_comments)
77
+ when /^(\w+)\s*\*\s*(\w+)\s*;/
78
+ type_name, field_name = $1, $2
79
+ yield process_type_hint(NFieldDef.new(field_name, PointerVarType.new(type_name)), eol_comments)
80
+ when /^id<(\w+)>\s+(\w+)\s*;/
81
+ type_name, field_name = $1, $2
82
+ yield process_type_hint(NFieldDef.new(field_name, IdVarType.new()), eol_comments)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def process_type_hint field_def, eol_comments
89
+ field_def.tags = (@tags + @this_line_tags).to_a
90
+
91
+ case field_def.type
92
+ when PointerVarType
93
+ case field_def.type.name
94
+ when 'NSArray'
95
+ if eol_comments =~ %r`//\s*of\s+(\w+)`
96
+ field_def.type.type_hint = $1
97
+ end
98
+ end
99
+ end
100
+
101
+ field_def
102
+ end
103
+ end
104
+
105
+ class PInterfaceHeader < Parser
106
+
107
+ def parse_line! line, eol_comments, indent
108
+ case line
109
+ when /^\{$/
110
+ yield NOpeningBrace.new
111
+ when /@end/
112
+ yield NEnd.new
113
+ when /^@property(\s*\([\w\s,]*\))?\s+(IBOutlet\s+)?(\w+)\s*\*\s*(\w+)\s*;$/
114
+ property_flags, iboutlet, type_name, property_name = $1, $2, $3, $4
115
+ yield NPropertyDef.new(property_name, PointerVarType.new(type_name))
116
+ when /^@property(\s*\([\w\s,]*\))?\s+(IBOutlet\s+)?(\w+)\s+(\w+)\s*;$/
117
+ property_flags, iboutlet, type_name, property_name = $1, $2, $3, $4
118
+ yield NPropertyDef.new(property_name, SimpleVarType.new(type_name))
119
+ when /^-\s*\(([^)]+)\)\s*(\w+[\w\s():*]*);$/
120
+ ret_type_decl, selector_decl = $1, $2
121
+ selector_def = SelectorDef.parse(selector_decl)
122
+ ret_type = VarType.parse(ret_type_decl)
123
+ yield NMethodHeader.new(selector_def, ret_type)
124
+
125
+ when /^-\s*\(([^)]+)\)\s*(\w+[\w\s():*]*)\{$/
126
+ ret_type_decl, selector_decl = $1, $2
127
+ selector_def = SelectorDef.parse(selector_decl)
128
+ ret_type = VarType.parse(ret_type_decl)
129
+ yield NMethodStart.new(selector_def, ret_type)
130
+
131
+ when /^@synthesize/
132
+ yield NSynthesize.parse(line)
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ class PMethodImpl < Parser
139
+
140
+ def parse_line! line, eol_comments, indent
141
+ case line
142
+ when /^\}$/
143
+ if indent == scope.start_node.indent
144
+ yield NMethodEnd.new
145
+ else
146
+ yield NClosingBrace.new
147
+ end
148
+ when /\[\s*([\w.]+)\s+release\s*\]/
149
+ expr = $1
150
+ yield NReleaseCall.new(expr)
151
+ when /\bself\s*\.\s*(\w+)\s*=\s*nil\s*[,;]/
152
+ expr = $1
153
+ yield NReleaseCall.new(expr)
154
+ when /\b(\w+)\s*=\s*nil\s*[,;]/
155
+ expr = $1
156
+ yield NReleaseCall.new(expr)
157
+ when /\[super\s/
158
+ yield NSuperCall.new
159
+ when /^return\b/
160
+ yield NReturn.new
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ end
@@ -0,0 +1,95 @@
1
+
2
+ module XDry
3
+
4
+ class SelectorDef
5
+
6
+ def self.parse string
7
+ string = string.strip
8
+ if string =~ /^\w+$/
9
+ SimpleSelectorDef.new(string)
10
+ else
11
+ comps = string.split(/\s+(?!\*)/).collect do |component_string|
12
+ if component_string =~ /^(\w+:)\s*(?:\(([^)]+)\)\s*)?(\w*)$/
13
+ keyword, type_decl, arg_name = $1, $2, $3
14
+ type = if type_decl then VarType.parse(type_decl) else nil end
15
+ SelectorComponent.new(keyword, arg_name, type)
16
+ else
17
+ raise StandardError, "Cannot parse selector component '#{component_string}' for selector '#{string}'"
18
+ end
19
+ end
20
+ CompoundSelectorDef.new(comps)
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ class SimpleSelectorDef < SelectorDef
27
+
28
+ attr_reader :selector
29
+
30
+ def initialize selector
31
+ @selector = selector
32
+ end
33
+
34
+ def simple?; true; end
35
+
36
+ def var_name_after_keyword keyword
37
+ nil
38
+ end
39
+
40
+ def to_s
41
+ @selector
42
+ end
43
+
44
+ end
45
+
46
+ class SelectorComponent
47
+ attr_reader :keyword, :arg_name, :type
48
+
49
+ def initialize keyword, arg_name, type
50
+ raise StandardError, "keyword must end with a colon: '#{keyword}'" unless keyword[-1] == ?:
51
+ @keyword, @arg_name, @type = keyword, arg_name, type
52
+ end
53
+
54
+ def keyword_without_colon
55
+ @keyword_without_colon ||= @keyword.sub(/:$/, '')
56
+ end
57
+
58
+ def has_type?
59
+ not @type.nil?
60
+ end
61
+
62
+ def to_s
63
+ if has_type?
64
+ "#{keyword}(#{@type})#{@arg_name}"
65
+ else
66
+ "#{keyword}#{@arg_name}"
67
+ end
68
+ end
69
+ end
70
+
71
+ class CompoundSelectorDef < SelectorDef
72
+ attr_reader :components
73
+
74
+ def initialize components
75
+ @components = components.freeze
76
+ end
77
+
78
+ def selector
79
+ @selector ||= @components.collect { |comp| comp.keyword }.join("")
80
+ end
81
+
82
+ def simple?; false; end
83
+
84
+ def to_s
85
+ @components.collect { |comp| comp.to_s }.join(" ")
86
+ end
87
+
88
+ def var_name_after_keyword keyword
89
+ comp = @components.find { |comp| comp.keyword == keyword }
90
+ comp && comp.arg_name
91
+ end
92
+
93
+ end
94
+
95
+ end