gyro 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +840 -0
- data/bin/gyro +118 -0
- data/lib/gyro.rb +32 -0
- data/lib/gyro/realm/java/converter.rb +63 -0
- data/lib/gyro/realm/java/enum_generator.rb +128 -0
- data/lib/gyro/realm/java/generator.rb +183 -0
- data/lib/gyro/realm/java/templates.rb +67 -0
- data/lib/gyro/realm/objc/converter.rb +63 -0
- data/lib/gyro/realm/objc/enum_generator.rb +86 -0
- data/lib/gyro/realm/objc/generator.rb +373 -0
- data/lib/gyro/realm/objc/json_category_generator.rb +172 -0
- data/lib/gyro/realm/objc/protocol_generator.rb +59 -0
- data/lib/gyro/realm/objc/templates.rb +100 -0
- data/lib/gyro/realm/swift/converter.rb +74 -0
- data/lib/gyro/realm/swift/enum_generator.rb +73 -0
- data/lib/gyro/realm/swift/generator.rb +265 -0
- data/lib/gyro/realm/swift/object_mapper_generator.rb +124 -0
- data/lib/gyro/realm/swift/templates.rb +64 -0
- data/lib/gyro/utils/file_utils.rb +31 -0
- data/lib/gyro/utils/log.rb +68 -0
- data/lib/gyro/utils/raise.rb +23 -0
- data/lib/gyro/utils/string_xcdatamodel.rb +58 -0
- data/lib/gyro/xcdatamodel/parser/attribute.rb +98 -0
- data/lib/gyro/xcdatamodel/parser/entity.rb +234 -0
- data/lib/gyro/xcdatamodel/parser/relationship.rb +70 -0
- data/lib/gyro/xcdatamodel/parser/xcdatamodel.rb +59 -0
- metadata +77 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module Gyro
|
18
|
+
|
19
|
+
def self.find_xcdatamodel(dir)
|
20
|
+
Dir.chdir(dir) do
|
21
|
+
files = Dir.glob('*.xcdatamodel')
|
22
|
+
files.first.nil? ? nil : File.expand_path(files.first, dir)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.write_file_with_name(dir, name_file, content)
|
27
|
+
file_path = File.expand_path(name_file, dir)
|
28
|
+
File.write(file_path, content)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module Gyro
|
18
|
+
module Log
|
19
|
+
|
20
|
+
def self.title(str) # bg yellow
|
21
|
+
puts "\e[44;37m#{str}\e[0m"
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.error(str)
|
25
|
+
puts "\e[1;31m! #{str}\e[0m"
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.info(str)
|
29
|
+
puts "\e[1;33m> #{str}\e[0m"
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.success(str)
|
33
|
+
puts "\e[1;32m√ #{str}\e[0m"
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.prompt(str, url = nil)
|
37
|
+
prompt = "\e[1;36m ! #{str} [y/n]?\e[0m "
|
38
|
+
url_info = ' '*10 + "\e[0;37m (use '?' to show in browser)\e[0m"
|
39
|
+
print prompt
|
40
|
+
print "#{url_info}\r#{prompt}" if url
|
41
|
+
|
42
|
+
answer = get_char do |c|
|
43
|
+
`open '#{url}'` if url && (c == '?')
|
44
|
+
"yn\003".include?(c.downcase) # \003 = ctrl-C
|
45
|
+
end
|
46
|
+
puts answer + (url ? ' '*url_info.length : '')
|
47
|
+
answer.downcase == 'y'
|
48
|
+
end
|
49
|
+
|
50
|
+
private ######################################################################
|
51
|
+
|
52
|
+
def self.get_char
|
53
|
+
stop = false
|
54
|
+
typed_char = ''
|
55
|
+
begin
|
56
|
+
system('stty raw -echo')
|
57
|
+
until stop
|
58
|
+
typed_char = STDIN.getc.chr
|
59
|
+
stop = yield typed_char
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
system('stty -raw echo')
|
63
|
+
end
|
64
|
+
typed_char
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module Raise
|
18
|
+
|
19
|
+
def self.error(str)
|
20
|
+
raise "\e[1;31m! #{str}\e[0m"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
class String
|
18
|
+
|
19
|
+
def delete_objc_prefix
|
20
|
+
i = 0
|
21
|
+
while i < self.length - 1 and /[[:upper:]]/.match(self[i+1])
|
22
|
+
i += 1
|
23
|
+
end
|
24
|
+
self[i..self.length]
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_inverse_suffix
|
28
|
+
self.gsub('_', '')
|
29
|
+
end
|
30
|
+
|
31
|
+
def capitalize_first_letter
|
32
|
+
self.slice(0, 1).capitalize + self.slice(1..-1)
|
33
|
+
end
|
34
|
+
|
35
|
+
def camel_case
|
36
|
+
words = self.scan(/[A-Z][a-z]+/)
|
37
|
+
words.map!(&:upcase)
|
38
|
+
words.join('_')
|
39
|
+
end
|
40
|
+
|
41
|
+
def underscore
|
42
|
+
self.gsub(/::/, '/').
|
43
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
44
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
45
|
+
tr('-', '_').
|
46
|
+
downcase
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_quotes
|
50
|
+
"\"" + self + "\""
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_parentheses
|
54
|
+
'(' + self + ')'
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module Gyro
|
18
|
+
module XCDataModel
|
19
|
+
module Parser
|
20
|
+
|
21
|
+
class Attribute
|
22
|
+
|
23
|
+
attr_accessor :entity_name, :name, :type, :optional, :indexed, :default
|
24
|
+
attr_accessor :realm_ignored, :realm_read_only, :enum_type, :enum_values
|
25
|
+
attr_accessor :json_key_path, :json_values, :transformer, :comment, :support_annotation
|
26
|
+
|
27
|
+
alias_method :optional?, :optional
|
28
|
+
alias_method :indexed?, :indexed
|
29
|
+
alias_method :realm_ignored?, :realm_ignored
|
30
|
+
|
31
|
+
def initialize (attribute_xml, entity_name)
|
32
|
+
@entity_name = entity_name
|
33
|
+
@name = attribute_xml.xpath('@name').to_s
|
34
|
+
@optional = attribute_xml.xpath('@optional').to_s == 'YES' ? true : false
|
35
|
+
@indexed = attribute_xml.xpath('@indexed').to_s == 'YES' ? true : false
|
36
|
+
@default = attribute_xml.xpath('@defaultValueString').to_s
|
37
|
+
@type = attribute_xml.xpath('@attributeType').to_s.downcase.gsub(' ', '_').to_sym
|
38
|
+
@realm_ignored = attribute_xml.xpath(USERINFO_VALUE%['realmIgnored']).to_s.empty? ? false : true
|
39
|
+
@realm_read_only = attribute_xml.xpath(USERINFO_VALUE%['realmReadOnly']).to_s
|
40
|
+
@enum_type = attribute_xml.xpath(USERINFO_VALUE%['enumType']).to_s
|
41
|
+
@enum_values = attribute_xml.xpath(USERINFO_VALUE%['enumValues']).to_s.split(',')
|
42
|
+
@json_key_path = attribute_xml.xpath(USERINFO_VALUE%['JSONKeyPath']).to_s
|
43
|
+
@json_values = attribute_xml.xpath(USERINFO_VALUE%['JSONValues']).to_s.split(',')
|
44
|
+
@transformer = attribute_xml.xpath(USERINFO_VALUE%['transformer']).to_s.strip
|
45
|
+
@comment = attribute_xml.xpath(USERINFO_VALUE%['comment']).to_s
|
46
|
+
@support_annotation = attribute_xml.xpath(USERINFO_VALUE%['supportAnnotation']).to_s
|
47
|
+
search_for_error
|
48
|
+
end
|
49
|
+
|
50
|
+
def enum?
|
51
|
+
!@enum_type.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_only?
|
55
|
+
!@realm_read_only.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_default?
|
59
|
+
!@default.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
"\tAttribute => name=#{@name} | type=#{@type} | optional=#{@optional} | default=#{@default} | indexed=#{@indexed}\n"
|
64
|
+
end
|
65
|
+
|
66
|
+
def is_decimal?
|
67
|
+
@type == :decimal or @type == :double or @type == :float
|
68
|
+
end
|
69
|
+
|
70
|
+
def is_integer?
|
71
|
+
@type == :integer_16 or @type == :integer_32 or @type == :integer_64
|
72
|
+
end
|
73
|
+
|
74
|
+
def is_number?
|
75
|
+
is_decimal? or is_integer?
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_bool?
|
79
|
+
@type == :boolean
|
80
|
+
end
|
81
|
+
|
82
|
+
def need_transformer?
|
83
|
+
!@enum_type.empty? or @type == :boolean or @type == :date or !@transformer.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
private ################################################################
|
87
|
+
|
88
|
+
def search_for_error
|
89
|
+
Raise::error("The attribute \"%s\" from \"%s\" has no type - please fix it"%[@name, @entity_name]) if @type == :undefined || @type.empty?
|
90
|
+
Raise::error("The attribute \"%s\" from \"%s\" is enum with incorrect type (not Integer) - please fix it"%[@name, @entity_name]) if !@enum_type.empty? and !@enum_values.empty? and !is_integer?
|
91
|
+
Raise::error("The attribute \"%s\" from \"%s\" is wrongly annotated: when declaring an type with enum and JSONKeyPath, you must have the same number of items in the 'enumValues' and 'JSONValues' annotations - please fix it"%[@name, @entity_name]) if !@json_key_path.empty? and !@enum_values.empty? and @enum_values.size != @json_values.size
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 - Niji
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
require 'nokogiri'
|
18
|
+
require 'set'
|
19
|
+
require File.expand_path('relationship', File.dirname(__FILE__))
|
20
|
+
require File.expand_path('attribute', File.dirname(__FILE__))
|
21
|
+
|
22
|
+
module Gyro
|
23
|
+
module XCDataModel
|
24
|
+
module Parser
|
25
|
+
class Entity
|
26
|
+
|
27
|
+
attr_accessor :name, :parent, :abstract, :attributes, :relationships, :identity_attribute, :comment
|
28
|
+
alias_method :abstract?, :abstract
|
29
|
+
|
30
|
+
def initialize(entity_xml)
|
31
|
+
@name = entity_xml.xpath('@name').to_s
|
32
|
+
@parent = entity_xml.xpath('@parentEntity').to_s
|
33
|
+
@abstract = entity_xml.xpath('@isAbstract').to_s == 'YES' ? true : false
|
34
|
+
@clean = false
|
35
|
+
@identity_attribute = entity_xml.xpath(USERINFO_VALUE%['identityAttribute']).to_s
|
36
|
+
@comment = entity_xml.xpath(USERINFO_VALUE%['comment']).to_s
|
37
|
+
@attributes = Hash.new
|
38
|
+
@relationships = Hash.new
|
39
|
+
load_entity(entity_xml)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
str = "\nEntity => #{@name}\n"
|
44
|
+
@attributes.each do |_, attribute|
|
45
|
+
str += attribute.to_s
|
46
|
+
end
|
47
|
+
@relationships.each do |_, relationship|
|
48
|
+
str += relationship.to_s
|
49
|
+
end
|
50
|
+
str
|
51
|
+
end
|
52
|
+
|
53
|
+
def used_as_list_by_other?(entities)
|
54
|
+
entities.each do |_, entity|
|
55
|
+
entity.relationships.each do |_, relationship|
|
56
|
+
return true if relationship.inverse_type == @name and relationship.type == :to_many
|
57
|
+
end
|
58
|
+
end
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
def has_list_attributes?(inverse = false)
|
63
|
+
@relationships.each do |_, relationship|
|
64
|
+
return true if relationship.type == :to_many and (!inverse ? !relationship.inverse? : true)
|
65
|
+
end
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_no_inverse_relationship?
|
70
|
+
@relationships.each do |_, relationship|
|
71
|
+
return true unless relationship.inverse?
|
72
|
+
end
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_ignored?
|
77
|
+
@attributes.each do |_, attribute|
|
78
|
+
return true if attribute.realm_ignored?
|
79
|
+
end
|
80
|
+
@relationships.each do |_, relationship|
|
81
|
+
return true if relationship.realm_ignored?
|
82
|
+
end
|
83
|
+
false
|
84
|
+
end
|
85
|
+
|
86
|
+
def has_primary_key?
|
87
|
+
!@identity_attribute.empty?
|
88
|
+
end
|
89
|
+
|
90
|
+
def has_required?
|
91
|
+
@attributes.each do |_, attribute|
|
92
|
+
return true if is_required?(attribute)
|
93
|
+
end
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def is_required?(attribute)
|
98
|
+
unless attribute.optional?
|
99
|
+
return true unless self.has_primary_key?
|
100
|
+
return true if self.has_primary_key? && !attribute.name.eql?(identity_attribute)
|
101
|
+
end
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
def has_default_value?(attribute = @identity_attribute)
|
106
|
+
attribute.name != @identity_attribute
|
107
|
+
end
|
108
|
+
|
109
|
+
def has_indexed_attributes?
|
110
|
+
@attributes.each do |_, attribute|
|
111
|
+
return true if attribute.indexed?
|
112
|
+
end
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
def has_json_key_path?
|
117
|
+
@attributes.each do |_, attribute|
|
118
|
+
return true unless attribute.json_key_path.empty?
|
119
|
+
end
|
120
|
+
@relationships.each do |_, relationship|
|
121
|
+
return true if !relationship.inverse? and !relationship.json_key_path.empty?
|
122
|
+
end
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
def has_enum_attributes?
|
127
|
+
@attributes.each do |_, attribute|
|
128
|
+
return true unless attribute.enum_type.empty?
|
129
|
+
end
|
130
|
+
false
|
131
|
+
end
|
132
|
+
|
133
|
+
def transformers
|
134
|
+
transformers = Set.new
|
135
|
+
@attributes.each do |_, attribute|
|
136
|
+
transformers.add attribute.transformer unless attribute.transformer.empty?
|
137
|
+
end
|
138
|
+
transformers
|
139
|
+
end
|
140
|
+
|
141
|
+
def has_custom_transformers?
|
142
|
+
@attributes.each do |_, attribute|
|
143
|
+
return true unless attribute.transformer.empty?
|
144
|
+
end
|
145
|
+
false
|
146
|
+
end
|
147
|
+
|
148
|
+
def need_transformer?
|
149
|
+
has_enum_attributes? || has_bool_attributes? || has_custom_transformers? || has_date_attribute?
|
150
|
+
end
|
151
|
+
|
152
|
+
def has_bool_attributes?
|
153
|
+
has_bool_attributes = false
|
154
|
+
@attributes.each do |_, attribute|
|
155
|
+
has_bool_attributes = true if attribute.type == :boolean
|
156
|
+
end
|
157
|
+
has_bool_attributes
|
158
|
+
end
|
159
|
+
|
160
|
+
def has_number_attributes?
|
161
|
+
has_number_attributes = false
|
162
|
+
@attributes.each do |_, attribute|
|
163
|
+
if attribute.enum_type.empty?
|
164
|
+
case attribute.type
|
165
|
+
when :integer_16 then
|
166
|
+
has_number_attributes = true
|
167
|
+
when :integer_32 then
|
168
|
+
has_number_attributes = true
|
169
|
+
when :integer_64 then
|
170
|
+
has_number_attributes = true
|
171
|
+
when :decimal then
|
172
|
+
has_number_attributes = true
|
173
|
+
when :double then
|
174
|
+
has_number_attributes = true
|
175
|
+
when :float then
|
176
|
+
has_number_attributes = true
|
177
|
+
else
|
178
|
+
has_number_attributes = false
|
179
|
+
end
|
180
|
+
break if has_number_attributes
|
181
|
+
end
|
182
|
+
end
|
183
|
+
has_number_attributes
|
184
|
+
end
|
185
|
+
|
186
|
+
def has_date_attribute?
|
187
|
+
@attributes.each do |_, attribute|
|
188
|
+
return true if attribute.type == :date
|
189
|
+
end
|
190
|
+
false
|
191
|
+
end
|
192
|
+
|
193
|
+
def has_list_relationship?
|
194
|
+
@relationships.each do |_, relationship|
|
195
|
+
return true unless relationship.destination.empty?
|
196
|
+
end
|
197
|
+
false
|
198
|
+
end
|
199
|
+
|
200
|
+
def has_only_inverse?
|
201
|
+
nb_inverses = 0
|
202
|
+
@relationships.each do |_, relationship|
|
203
|
+
nb_inverses+=1 if relationship.inverse?
|
204
|
+
end
|
205
|
+
nb_inverses==@relationships.size
|
206
|
+
end
|
207
|
+
|
208
|
+
private ################################################################
|
209
|
+
|
210
|
+
def load_entity(entity_xml)
|
211
|
+
load_attributes(entity_xml)
|
212
|
+
load_relationships(entity_xml)
|
213
|
+
end
|
214
|
+
|
215
|
+
def load_attributes(entity_xml)
|
216
|
+
entity_xml.xpath('attribute').each do |node|
|
217
|
+
attribute = Attribute.new(node, @name)
|
218
|
+
if attribute.type != 'Transformable'
|
219
|
+
@attributes[attribute.name] = attribute
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def load_relationships(entity_xml)
|
225
|
+
entity_xml.xpath('relationship').each do |node|
|
226
|
+
relationship = Relationship.new(node, @name)
|
227
|
+
@relationships[relationship.name] = relationship
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|