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