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,66 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
class VarType
|
5
|
+
def self.parse type_decl
|
6
|
+
type_decl = type_decl.strip
|
7
|
+
case type_decl
|
8
|
+
when /^id$/
|
9
|
+
IdVarType.new
|
10
|
+
when /^(?:unsigned\s+|signed\s+|long\s+)?\w+$/
|
11
|
+
SimpleVarType.new(type_decl.gsub(/\s+/, ' '))
|
12
|
+
when /^(\w+)\s*\*$/
|
13
|
+
class_name = $1
|
14
|
+
PointerVarType.new(class_name)
|
15
|
+
else
|
16
|
+
raise StandardError, "Cannot parse Obj-C type: '#{type_decl}'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_source_with_space
|
21
|
+
needs_space? ? "#{to_s} " : "#{to_s}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def needs_space?; true; end
|
25
|
+
end
|
26
|
+
|
27
|
+
class IdVarType < VarType
|
28
|
+
def to_s
|
29
|
+
"id"
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_property_retainment_policy; 'assign'; end
|
33
|
+
end
|
34
|
+
|
35
|
+
class SimpleVarType < VarType
|
36
|
+
attr_reader :name
|
37
|
+
|
38
|
+
def initialize name
|
39
|
+
@name = name
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
"#{@name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_property_retainment_policy; ''; end
|
47
|
+
end
|
48
|
+
|
49
|
+
class PointerVarType < VarType
|
50
|
+
attr_reader :name
|
51
|
+
attr_accessor :type_hint
|
52
|
+
|
53
|
+
def initialize name
|
54
|
+
@name = name
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
"#{@name} *"
|
59
|
+
end
|
60
|
+
|
61
|
+
def needs_space?; false; end
|
62
|
+
|
63
|
+
def default_property_retainment_policy; 'retain'; end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
class BaseFileRef
|
5
|
+
|
6
|
+
attr_reader :positions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@positions = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_pos! pos
|
13
|
+
@positions << pos
|
14
|
+
end
|
15
|
+
|
16
|
+
def fixup_positions! after_line_no, offset
|
17
|
+
@positions.each { |pos| pos.fixup! after_line_no, offset }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class FileRef < BaseFileRef
|
23
|
+
|
24
|
+
attr_reader :path
|
25
|
+
|
26
|
+
def initialize path
|
27
|
+
super()
|
28
|
+
@path = path
|
29
|
+
end
|
30
|
+
|
31
|
+
def read
|
32
|
+
open(@path) { |f| f.read }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class TestFileRef < BaseFileRef
|
38
|
+
attr_reader :path
|
39
|
+
|
40
|
+
def initialize path, source
|
41
|
+
super()
|
42
|
+
@path, @source = path, source
|
43
|
+
end
|
44
|
+
|
45
|
+
def read
|
46
|
+
@source
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Pos
|
51
|
+
attr_reader :file_ref, :line_no
|
52
|
+
attr_accessor :scope_before, :scope_after
|
53
|
+
|
54
|
+
def initialize file_ref, line_no
|
55
|
+
@file_ref = file_ref
|
56
|
+
@line_no = line_no
|
57
|
+
@file_ref.add_pos! self
|
58
|
+
end
|
59
|
+
|
60
|
+
def file_path
|
61
|
+
@file_ref.path
|
62
|
+
end
|
63
|
+
|
64
|
+
def fixup! after_line_no, offset
|
65
|
+
if @line_no > after_line_no
|
66
|
+
@line_no += offset
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
"#{File.basename(@file_ref.path)}:#{@line_no}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
class ScopeStack
|
5
|
+
|
6
|
+
attr_accessor :verbose
|
7
|
+
|
8
|
+
def initialize root_scopes
|
9
|
+
@stack = []
|
10
|
+
root_scopes.each { |scope| push(scope) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_line line, eol_comments, indent
|
14
|
+
parse_line_using_parser! line, eol_comments, indent do |node|
|
15
|
+
unless node.nil? # to simply code we allow the parser to yield nil when it cannot parse something
|
16
|
+
# update the scope based on this new node
|
17
|
+
while @current_scope.ends_after? node
|
18
|
+
yield @current_scope, node
|
19
|
+
pop
|
20
|
+
end
|
21
|
+
if subscope = @current_scope.subscope_for(node)
|
22
|
+
# a subscope is added as a child of its parent scope
|
23
|
+
yield @current_scope, subscope
|
24
|
+
subscope.assert_bound!
|
25
|
+
push subscope
|
26
|
+
end
|
27
|
+
# add the new node to the scope we have finally decided on
|
28
|
+
yield @current_scope, node
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def current_scope
|
34
|
+
@current_scope
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def parse_line_using_parser! line, eol_comments, indent
|
40
|
+
parsed = false
|
41
|
+
@current_scope.parser.parse_line! line, eol_comments, indent do |node|
|
42
|
+
parsed = true
|
43
|
+
yield node
|
44
|
+
end
|
45
|
+
unless parsed
|
46
|
+
yield NLine.new(line)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def push subscope
|
51
|
+
raise StandardError, "Attempted to push a nil subscope" if subscope.nil?
|
52
|
+
@stack.push subscope
|
53
|
+
update_current_scope
|
54
|
+
end
|
55
|
+
|
56
|
+
def pop
|
57
|
+
@stack.pop
|
58
|
+
update_current_scope
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_current_scope
|
62
|
+
old_scope, @current_scope = @current_scope, @stack[-1]
|
63
|
+
puts "#{old_scope} --> #{@current_scope}" if @verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
class SMethodImpl < ChildScope
|
5
|
+
|
6
|
+
parse_using PMethodImpl
|
7
|
+
|
8
|
+
on NMethodEnd, :pop, :store_into => :end_node
|
9
|
+
|
10
|
+
def selector
|
11
|
+
@start_node.selector
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class SInterfaceFields < ChildScope
|
17
|
+
|
18
|
+
parse_using PInterfaceFields
|
19
|
+
|
20
|
+
on NInterfaceFieldsEnd, :pop, :store_into => :end_node
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class SInterface < ChildScope
|
25
|
+
|
26
|
+
parse_using PInterfaceHeader
|
27
|
+
|
28
|
+
on NEnd, :pop, :store_into => :end_node
|
29
|
+
on NOpeningBrace, :start => SInterfaceFields
|
30
|
+
on SInterfaceFields, :store_into => :fields_scope
|
31
|
+
|
32
|
+
def class_name
|
33
|
+
@start_node.class_name
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class SImplementation < ChildScope
|
39
|
+
|
40
|
+
parse_using PInterfaceHeader
|
41
|
+
|
42
|
+
on NEnd, :pop
|
43
|
+
on NSynthesize, :add_to => :synthesizes
|
44
|
+
on NMethodStart, :start => SMethodImpl
|
45
|
+
|
46
|
+
def class_name
|
47
|
+
@start_node.class_name
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
class SFile < Scope
|
53
|
+
|
54
|
+
parse_using PGlobal
|
55
|
+
|
56
|
+
on NInterfaceStart, :start => SInterface
|
57
|
+
on NImplementationStart, :start => SImplementation
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
|
2
|
+
module XDry
|
3
|
+
|
4
|
+
class Scope
|
5
|
+
|
6
|
+
attr_reader :model
|
7
|
+
attr_reader :children
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@children = []
|
11
|
+
self.class.child_collections.each do |var_name|
|
12
|
+
instance_variable_set("@#{var_name}", [])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def bind model
|
17
|
+
raise StandardError, "#{self} already bound to #{@model} when trying to bind to #{model}" unless @model.nil?
|
18
|
+
@model = model
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_bound!
|
23
|
+
raise StandardError, "#{self.class.name} hasn't been bound to a model" if @model.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def parser
|
27
|
+
@parser ||= create_parser
|
28
|
+
end
|
29
|
+
|
30
|
+
def subscope_for node
|
31
|
+
if subscope_class = self.class.child_subscope_table[node.class]
|
32
|
+
subscope_class.new(self, node)
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def ends_after? node
|
39
|
+
self.class.stop_children.include? node.class
|
40
|
+
end
|
41
|
+
|
42
|
+
def << child
|
43
|
+
raise StandardError, "#{self.class.name} hasn't been bound to a model, but is trying to accept a child #{child}" if @model.nil?
|
44
|
+
@children << child
|
45
|
+
@model << child
|
46
|
+
child_added child
|
47
|
+
end
|
48
|
+
|
49
|
+
def child_added child
|
50
|
+
(self.class.child_action_table[child.class] || []).each { |action| action.call(self, child) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"#{self.class.name}:#{@model}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent_scopes
|
58
|
+
[]
|
59
|
+
end
|
60
|
+
|
61
|
+
def all_scopes
|
62
|
+
parent_scopes + [self]
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def create_parser
|
68
|
+
return self.class.parser_class.new(self) if self.class.parser_class
|
69
|
+
raise StandardError, "#{self.class.name} does not override create_parser"
|
70
|
+
end
|
71
|
+
|
72
|
+
class << self
|
73
|
+
|
74
|
+
attr_reader :parser_class
|
75
|
+
|
76
|
+
def parse_using parser_class
|
77
|
+
@parser_class = parser_class
|
78
|
+
end
|
79
|
+
|
80
|
+
# on NSome, :pop, :store_into => :my_var
|
81
|
+
# on NOther, :start => SOther
|
82
|
+
# on NAwesome, :add_to => :awesomes
|
83
|
+
def on child_class, *args
|
84
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
85
|
+
if args.include? :pop
|
86
|
+
stop_children << child_class
|
87
|
+
end
|
88
|
+
if options[:start]
|
89
|
+
child_subscope_table[child_class] = options[:start]
|
90
|
+
end
|
91
|
+
if var_name = options[:store_into]
|
92
|
+
(child_action_table[child_class] ||= []) << lambda do |instance, child|
|
93
|
+
instance.send(:instance_variable_set, "@#{var_name}", child)
|
94
|
+
end
|
95
|
+
attr_reader :"#{var_name}"
|
96
|
+
end
|
97
|
+
if coll_name = options[:add_to]
|
98
|
+
(child_action_table[child_class] ||= []) << lambda do |instance, child|
|
99
|
+
instance.send(:instance_variable_get, "@#{coll_name}") << child
|
100
|
+
end
|
101
|
+
child_collections << coll_name
|
102
|
+
attr_reader :"#{coll_name}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop_children
|
107
|
+
@stop_children ||= []
|
108
|
+
end
|
109
|
+
|
110
|
+
def child_subscope_table
|
111
|
+
@child_subscope_table ||= {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def child_action_table
|
115
|
+
@child_action_table ||= {}
|
116
|
+
end
|
117
|
+
|
118
|
+
def child_collections
|
119
|
+
@child_collections ||= []
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
class ChildScope < Scope
|
127
|
+
|
128
|
+
attr_reader :start_node
|
129
|
+
attr_reader :parent_scope
|
130
|
+
|
131
|
+
def initialize parent_scope, start_node
|
132
|
+
super()
|
133
|
+
@parent_scope = parent_scope
|
134
|
+
@start_node = start_node
|
135
|
+
end
|
136
|
+
|
137
|
+
def parent_scopes
|
138
|
+
parent_scope.all_scopes
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module XDry
|
2
|
+
|
3
|
+
class Emitter
|
4
|
+
attr_reader :lines
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@lines = []
|
8
|
+
@indent = "\t"
|
9
|
+
@current_indent = ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.capture
|
13
|
+
emitter = Emitter.new
|
14
|
+
yield emitter
|
15
|
+
return emitter.lines
|
16
|
+
end
|
17
|
+
|
18
|
+
def << line
|
19
|
+
case line
|
20
|
+
when Emitter
|
21
|
+
@lines.push *line.lines.collect { |l| @current_indent + l }
|
22
|
+
when Array
|
23
|
+
@lines.push *line.collect { |l| @current_indent + l }
|
24
|
+
else
|
25
|
+
@lines << @current_indent + line
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def indent
|
30
|
+
prev_indent = @current_indent
|
31
|
+
@current_indent = @current_indent + @indent
|
32
|
+
yield
|
33
|
+
@current_indent = prev_indent
|
34
|
+
end
|
35
|
+
|
36
|
+
def empty?
|
37
|
+
@lines.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
@lines.collect { |line| line + "\n" }.join("")
|
42
|
+
end
|
43
|
+
|
44
|
+
def block prefix = ''
|
45
|
+
self << "#{prefix} {"
|
46
|
+
self.indent { yield }
|
47
|
+
self << "}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def method decl, &block
|
51
|
+
self << ""
|
52
|
+
self.block "- #{decl}", &block
|
53
|
+
end
|
54
|
+
|
55
|
+
def if condition, &block
|
56
|
+
self.block "if (#{condition})", &block
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|