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,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
|