neo4j 4.0.0 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/Gemfile +6 -16
- data/README.md +5 -2
- data/bin/neo4j-jars +6 -6
- data/lib/neo4j.rb +13 -9
- data/lib/neo4j/active_node.rb +9 -9
- data/lib/neo4j/active_node/dependent.rb +11 -0
- data/lib/neo4j/active_node/dependent/association_methods.rb +28 -0
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +48 -0
- data/lib/neo4j/active_node/has_n.rb +124 -112
- data/lib/neo4j/active_node/has_n/association.rb +45 -30
- data/lib/neo4j/active_node/id_property.rb +22 -19
- data/lib/neo4j/active_node/initialize.rb +2 -4
- data/lib/neo4j/active_node/labels.rb +23 -22
- data/lib/neo4j/active_node/node_wrapper.rb +5 -8
- data/lib/neo4j/active_node/orm_adapter.rb +2 -4
- data/lib/neo4j/active_node/persistence.rb +5 -10
- data/lib/neo4j/active_node/property.rb +3 -4
- data/lib/neo4j/active_node/query.rb +27 -6
- data/lib/neo4j/active_node/query/query_proxy.rb +65 -110
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +67 -0
- data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +0 -1
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +29 -28
- data/lib/neo4j/active_node/query_methods.rb +6 -6
- data/lib/neo4j/active_node/reflection.rb +3 -2
- data/lib/neo4j/active_node/rels.rb +1 -1
- data/lib/neo4j/active_node/scope.rb +13 -8
- data/lib/neo4j/active_node/validations.rb +5 -6
- data/lib/neo4j/active_rel.rb +1 -2
- data/lib/neo4j/active_rel/callbacks.rb +3 -3
- data/lib/neo4j/active_rel/persistence.rb +9 -7
- data/lib/neo4j/active_rel/property.rb +12 -4
- data/lib/neo4j/active_rel/query.rb +6 -8
- data/lib/neo4j/active_rel/rel_wrapper.rb +0 -2
- data/lib/neo4j/active_rel/related_node.rb +4 -5
- data/lib/neo4j/active_rel/types.rb +4 -6
- data/lib/neo4j/active_rel/validations.rb +0 -1
- data/lib/neo4j/config.rb +11 -23
- data/lib/neo4j/core/query.rb +1 -1
- data/lib/neo4j/migration.rb +17 -18
- data/lib/neo4j/paginated.rb +4 -4
- data/lib/neo4j/railtie.rb +19 -19
- data/lib/neo4j/shared.rb +7 -3
- data/lib/neo4j/shared/callbacks.rb +15 -4
- data/lib/neo4j/shared/identity.rb +2 -2
- data/lib/neo4j/shared/persistence.rb +10 -21
- data/lib/neo4j/shared/property.rb +17 -30
- data/lib/neo4j/shared/rel_type_converters.rb +1 -3
- data/lib/neo4j/shared/type_converters.rb +13 -25
- data/lib/neo4j/shared/validations.rb +3 -3
- data/lib/neo4j/tasks/migration.rake +7 -7
- data/lib/neo4j/type_converters.rb +1 -1
- data/lib/neo4j/version.rb +1 -1
- data/lib/rails/generators/neo4j/model/model_generator.rb +16 -12
- data/lib/rails/generators/neo4j_generator.rb +18 -18
- data/neo4j.gemspec +22 -18
- metadata +103 -1
@@ -5,16 +5,16 @@ module Neo4j
|
|
5
5
|
module HasN
|
6
6
|
class Association
|
7
7
|
include Neo4j::Shared::RelTypeConverters
|
8
|
-
|
8
|
+
include Neo4j::ActiveNode::Dependent::AssociationMethods
|
9
|
+
attr_reader :type, :name, :relationship, :direction, :dependent
|
9
10
|
|
10
11
|
def initialize(type, direction, name, options = {})
|
11
|
-
|
12
|
+
validate_init_arguments(type, direction, options)
|
12
13
|
@type = type.to_sym
|
13
14
|
@name = name
|
14
15
|
@direction = direction.to_sym
|
15
16
|
@target_class_name_from_name = name.to_s.classify
|
16
|
-
|
17
|
-
set_vars_from_options(options)
|
17
|
+
apply_vars_from_options(options)
|
18
18
|
end
|
19
19
|
|
20
20
|
def target_class_option(options)
|
@@ -42,7 +42,11 @@ module Neo4j
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def target_class_name
|
45
|
-
@target_class_option.to_s if @target_class_option
|
45
|
+
@target_class_name ||= @target_class_option.to_s if @target_class_option
|
46
|
+
end
|
47
|
+
|
48
|
+
def target_class_name_or_nil
|
49
|
+
@target_class_name_or_nil ||= target_class_name || 'nil'
|
46
50
|
end
|
47
51
|
|
48
52
|
def target_class
|
@@ -75,9 +79,7 @@ module Neo4j
|
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
|
79
|
-
@relationship_class
|
80
|
-
end
|
82
|
+
attr_reader :relationship_class
|
81
83
|
|
82
84
|
def relationship_class_type
|
83
85
|
@relationship_class = @relationship_class.constantize if @relationship_class.class == String || @relationship_class == Symbol
|
@@ -104,6 +106,10 @@ module Neo4j
|
|
104
106
|
properties
|
105
107
|
end
|
106
108
|
|
109
|
+
def unique?
|
110
|
+
@origin ? origin_association.unique? : !!@unique
|
111
|
+
end
|
112
|
+
|
107
113
|
private
|
108
114
|
|
109
115
|
def get_direction(relationship_cypher, create)
|
@@ -129,19 +135,24 @@ module Neo4j
|
|
129
135
|
p.size == 0 ? '' : " {#{p}}"
|
130
136
|
end
|
131
137
|
|
138
|
+
def origin_association
|
139
|
+
target_class.associations[@origin]
|
140
|
+
end
|
141
|
+
|
132
142
|
def origin_type
|
133
|
-
|
143
|
+
origin_association.relationship_type
|
134
144
|
end
|
135
145
|
|
136
146
|
private
|
137
147
|
|
138
|
-
def
|
139
|
-
validate_option_combinations(options)
|
148
|
+
def apply_vars_from_options(options)
|
140
149
|
@target_class_option = target_class_option(options)
|
141
150
|
@callbacks = {before: options[:before], after: options[:after]}
|
142
151
|
@origin = options[:origin] && options[:origin].to_sym
|
143
152
|
@relationship_class = options[:rel_class]
|
144
153
|
@relationship_type = options[:type] && options[:type].to_sym
|
154
|
+
@dependent = options[:dependent]
|
155
|
+
@unique = options[:unique]
|
145
156
|
end
|
146
157
|
|
147
158
|
# Return basic details about association as declared in the model
|
@@ -151,15 +162,25 @@ module Neo4j
|
|
151
162
|
"#{type} #{direction.inspect}, #{name.inspect}"
|
152
163
|
end
|
153
164
|
|
165
|
+
def validate_init_arguments(type, direction, options)
|
166
|
+
validate_option_combinations(options)
|
167
|
+
check_valid_type_and_dir(type, direction)
|
168
|
+
end
|
169
|
+
|
154
170
|
def check_valid_type_and_dir(type, direction)
|
155
|
-
|
156
|
-
|
171
|
+
fail ArgumentError, "Invalid association type: #{type.inspect} (valid value: :has_many and :has_one)" if not [:has_many, :has_one].include?(type.to_sym)
|
172
|
+
fail ArgumentError, "Invalid direction: #{direction.inspect} (valid value: :out, :in, and :both)" if not [:out, :in, :both].include?(direction.to_sym)
|
157
173
|
end
|
158
174
|
|
159
175
|
def validate_option_combinations(options)
|
160
|
-
|
161
|
-
|
162
|
-
|
176
|
+
fail ArgumentError, "Cannot specify both :type and :origin (#{base_declaration})" if options[:type] && options[:origin]
|
177
|
+
fail ArgumentError, "Cannot specify both :type and :rel_class (#{base_declaration})" if options[:type] && options[:rel_class]
|
178
|
+
fail ArgumentError, "Cannot specify both :origin and :rel_class (#{base_declaration}" if options[:origin] && options[:rel_class]
|
179
|
+
end
|
180
|
+
|
181
|
+
VALID_DEPENDENT_TYPES = [:delete, :delete_orphans, :destroy_orphans, :destroy, nil]
|
182
|
+
def validate_dependent(value)
|
183
|
+
fail ArgumentError, "Invalid dependent value: #{value.inspect}" if not VALID_DEPENDENT_TYPES.include?(value)
|
163
184
|
end
|
164
185
|
|
165
186
|
# Determine if model class as derived from the association name would be different than the one specified via the model_class key
|
@@ -174,22 +195,16 @@ module Neo4j
|
|
174
195
|
end
|
175
196
|
|
176
197
|
def validate_origin!
|
177
|
-
if @origin
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
end
|
186
|
-
else
|
187
|
-
raise ArgumentError, "Cannot use :origin without a model_class (implied or explicit)"
|
188
|
-
end
|
189
|
-
end
|
198
|
+
return if not @origin
|
199
|
+
|
200
|
+
fail ArgumentError, 'Cannot use :origin without a model_class (implied or explicit)' if not target_class
|
201
|
+
|
202
|
+
association = origin_association
|
203
|
+
fail ArgumentError, "Origin `#{@origin.inspect}` association not found for #{target_class} (specified in #{base_declaration})" if not association
|
204
|
+
|
205
|
+
fail ArgumentError, "Origin `#{@origin.inspect}` (specified in #{base_declaration}) has same direction `#{@direction}`)" if @direction == association.direction
|
190
206
|
end
|
191
207
|
end
|
192
208
|
end
|
193
209
|
end
|
194
210
|
end
|
195
|
-
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Neo4j::ActiveNode
|
2
|
-
|
3
2
|
# This module makes it possible to use other IDs than the build it neo4j id (neo_id)
|
4
3
|
#
|
5
4
|
# @example using generated UUIDs
|
@@ -27,16 +26,16 @@ module Neo4j::ActiveNode
|
|
27
26
|
|
28
27
|
module TypeMethods
|
29
28
|
def define_id_methods(clazz, name, conf)
|
30
|
-
|
29
|
+
fail "Expected a Hash, got #{conf.class} (#{conf}) for id_property" unless conf.is_a?(Hash)
|
31
30
|
if conf[:on]
|
32
31
|
define_custom_method(clazz, name, conf[:on])
|
33
32
|
elsif conf[:auto]
|
34
|
-
|
33
|
+
fail "only :uuid auto id_property allowed, got #{conf[:auto]}" unless conf[:auto] == :uuid
|
35
34
|
define_uuid_method(clazz, name)
|
36
35
|
elsif conf.empty?
|
37
36
|
define_property_method(clazz, name)
|
38
37
|
else
|
39
|
-
|
38
|
+
fail "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
@@ -45,23 +44,22 @@ module Neo4j::ActiveNode
|
|
45
44
|
def define_property_method(clazz, name)
|
46
45
|
clear_methods(clazz, name)
|
47
46
|
|
48
|
-
clazz.module_eval(%
|
47
|
+
clazz.module_eval(%(
|
49
48
|
def id
|
50
|
-
|
49
|
+
_persisted_obj ? #{name.to_sym == :id ? 'attribute(\'id\')' : name} : nil
|
51
50
|
end
|
52
51
|
|
53
52
|
validates_uniqueness_of :#{name}
|
54
53
|
|
55
54
|
property :#{name}
|
56
|
-
|
57
|
-
|
55
|
+
), __FILE__, __LINE__)
|
58
56
|
end
|
59
57
|
|
60
58
|
|
61
59
|
def define_uuid_method(clazz, name)
|
62
60
|
clear_methods(clazz, name)
|
63
61
|
|
64
|
-
clazz.module_eval(%
|
62
|
+
clazz.module_eval(%(
|
65
63
|
default_property :#{name} do
|
66
64
|
::SecureRandom.uuid
|
67
65
|
end
|
@@ -71,13 +69,13 @@ module Neo4j::ActiveNode
|
|
71
69
|
end
|
72
70
|
|
73
71
|
alias_method :id, :#{name}
|
74
|
-
|
72
|
+
), __FILE__, __LINE__)
|
75
73
|
end
|
76
74
|
|
77
75
|
def define_custom_method(clazz, name, on)
|
78
76
|
clear_methods(clazz, name)
|
79
77
|
|
80
|
-
clazz.module_eval(%
|
78
|
+
clazz.module_eval(%{
|
81
79
|
default_property :#{name} do |instance|
|
82
80
|
raise "Specifying custom id_property #{name} on none existing method #{on}" unless instance.respond_to?(:#{on})
|
83
81
|
instance.#{on}
|
@@ -93,15 +91,15 @@ module Neo4j::ActiveNode
|
|
93
91
|
|
94
92
|
def clear_methods(clazz, name)
|
95
93
|
if clazz.method_defined?(name)
|
96
|
-
clazz.module_eval(%
|
94
|
+
clazz.module_eval(%(
|
97
95
|
undef_method :#{name}
|
98
|
-
|
96
|
+
), __FILE__, __LINE__)
|
99
97
|
end
|
100
98
|
|
101
99
|
if clazz.attribute_names.include?(name.to_s)
|
102
|
-
clazz.module_eval(%
|
100
|
+
clazz.module_eval(%(
|
103
101
|
undef_property :#{name}
|
104
|
-
|
102
|
+
), __FILE__, __LINE__)
|
105
103
|
end
|
106
104
|
end
|
107
105
|
|
@@ -110,7 +108,6 @@ module Neo4j::ActiveNode
|
|
110
108
|
|
111
109
|
|
112
110
|
module ClassMethods
|
113
|
-
|
114
111
|
def find_by_neo_id(id)
|
115
112
|
Neo4j::Node.load(id)
|
116
113
|
end
|
@@ -125,7 +122,7 @@ module Neo4j::ActiveNode
|
|
125
122
|
|
126
123
|
def id_property(name, conf = {})
|
127
124
|
begin
|
128
|
-
if
|
125
|
+
if id_property?
|
129
126
|
unless mapped_label.uniqueness_constraints[:property_keys].include?([name])
|
130
127
|
drop_constraint(id_property_name, type: :unique)
|
131
128
|
end
|
@@ -142,7 +139,15 @@ module Neo4j::ActiveNode
|
|
142
139
|
end
|
143
140
|
end
|
144
141
|
|
142
|
+
# rubocop:disable Style/PredicateName
|
145
143
|
def has_id_property?
|
144
|
+
ActiveSupport::Deprecation.warn 'has_id_property? is deprecated and may be removed from future releases, use id_property? instead.', caller
|
145
|
+
|
146
|
+
id_property?
|
147
|
+
end
|
148
|
+
# rubocop:enable Style/PredicateName
|
149
|
+
|
150
|
+
def id_property?
|
146
151
|
id_property_info && !id_property_info.empty?
|
147
152
|
end
|
148
153
|
|
@@ -155,8 +160,6 @@ module Neo4j::ActiveNode
|
|
155
160
|
end
|
156
161
|
|
157
162
|
alias_method :primary_key, :id_property_name
|
158
|
-
|
159
163
|
end
|
160
164
|
end
|
161
|
-
|
162
165
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Neo4j::ActiveNode::Initialize
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
include Neo4j::Shared::TypeConverters
|
4
|
+
attr_reader :called_by
|
4
5
|
|
5
6
|
# called when loading the node from the database
|
6
7
|
# @param [Neo4j::Node] persisted_node the node this class wraps
|
@@ -11,7 +12,7 @@ module Neo4j::ActiveNode::Initialize
|
|
11
12
|
@association_cache = {}
|
12
13
|
changed_attributes && changed_attributes.clear
|
13
14
|
@attributes = attributes.merge(properties.stringify_keys)
|
14
|
-
self.default_properties=properties
|
15
|
+
self.default_properties = properties
|
15
16
|
@attributes = convert_properties_to :ruby, @attributes
|
16
17
|
end
|
17
18
|
|
@@ -21,7 +22,4 @@ module Neo4j::ActiveNode::Initialize
|
|
21
22
|
def wrapper
|
22
23
|
self
|
23
24
|
end
|
24
|
-
|
25
25
|
end
|
26
|
-
|
27
|
-
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module Neo4j
|
2
2
|
module ActiveNode
|
3
|
-
|
4
|
-
|
5
3
|
# Provides a mapping between neo4j labels and Ruby classes
|
6
4
|
module Labels
|
7
5
|
extend ActiveSupport::Concern
|
@@ -52,7 +50,7 @@ module Neo4j
|
|
52
50
|
# Only for testing purpose
|
53
51
|
# @private
|
54
52
|
def self._wrapped_labels=(wl)
|
55
|
-
@_wrapped_labels=(wl)
|
53
|
+
@_wrapped_labels = (wl)
|
56
54
|
end
|
57
55
|
|
58
56
|
def self._wrapped_labels
|
@@ -74,25 +72,24 @@ module Neo4j
|
|
74
72
|
# Returns the object with the specified neo4j id.
|
75
73
|
# @param [String,Fixnum] id of node to find
|
76
74
|
def find(id)
|
77
|
-
map_id =
|
75
|
+
map_id = proc { |object| object.respond_to?(:id) ? object.send(:id) : object }
|
78
76
|
|
79
77
|
if id.is_a?(Array)
|
80
|
-
find_by_ids(id.map {|o| map_id.call(o) })
|
78
|
+
find_by_ids(id.map { |o| map_id.call(o) })
|
81
79
|
else
|
82
80
|
find_by_id(map_id.call(id))
|
83
81
|
end
|
84
82
|
end
|
85
83
|
|
86
84
|
# Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.
|
87
|
-
# @param
|
88
|
-
def find_by(
|
89
|
-
self.query_as(:n).where(n:
|
85
|
+
# @param Hash args of arguments to find
|
86
|
+
def find_by(values)
|
87
|
+
self.query_as(:n).where(n: values).limit(1).pluck(:n).first
|
90
88
|
end
|
91
89
|
|
92
90
|
# Like find_by, except that if no record is found, raises a RecordNotFound error.
|
93
|
-
def find_by!(
|
94
|
-
|
95
|
-
find_by(args) or raise RecordNotFound, "#{self.query_as(:n).where(n: a).limit(1).to_cypher} returned no results"
|
91
|
+
def find_by!(values)
|
92
|
+
find_by(values) || fail(RecordNotFound, "#{self.query_as(:n).where(n: values).limit(1).to_cypher} returned no results")
|
96
93
|
end
|
97
94
|
|
98
95
|
# Deletes all nodes and connected relationships from Cypher.
|
@@ -104,7 +101,7 @@ module Neo4j
|
|
104
101
|
# Returns each node to Ruby and calls `destroy`. Be careful, as this can be a very slow operation if you have many nodes. It will generate at least
|
105
102
|
# one database query per node in the database, more if callbacks require them.
|
106
103
|
def destroy_all
|
107
|
-
self.all.each
|
104
|
+
self.all.each(&:destroy)
|
108
105
|
end
|
109
106
|
|
110
107
|
# Creates a Neo4j index on given property
|
@@ -141,14 +138,14 @@ module Neo4j
|
|
141
138
|
# @example
|
142
139
|
# Person.constraint :name, type: :unique
|
143
140
|
#
|
144
|
-
def constraint(property, constraints
|
141
|
+
def constraint(property, constraints)
|
145
142
|
Neo4j::Session.on_session_available do |session|
|
146
143
|
label = Neo4j::Label.create(mapped_label_name)
|
147
144
|
label.create_constraint(property, constraints, session)
|
148
145
|
end
|
149
146
|
end
|
150
147
|
|
151
|
-
def drop_constraint(property, constraint
|
148
|
+
def drop_constraint(property, constraint)
|
152
149
|
Neo4j::Session.on_session_available do |session|
|
153
150
|
label = Neo4j::Label.create(mapped_label_name)
|
154
151
|
label.drop_constraint(property, constraint, session)
|
@@ -166,7 +163,7 @@ module Neo4j
|
|
166
163
|
|
167
164
|
# @return [Symbol] the label that this class has which corresponds to a Ruby class
|
168
165
|
def mapped_label_name
|
169
|
-
@
|
166
|
+
@mapped_label_name || (self.name.nil? ? object_id.to_s.to_sym : self.name.to_sym)
|
170
167
|
end
|
171
168
|
|
172
169
|
# @return [Neo4j::Label] the label for this class
|
@@ -180,7 +177,7 @@ module Neo4j
|
|
180
177
|
|
181
178
|
def base_class
|
182
179
|
unless self < Neo4j::ActiveNode
|
183
|
-
|
180
|
+
fail "#{name} doesn't belong in a hierarchy descending from ActiveNode"
|
184
181
|
end
|
185
182
|
|
186
183
|
if superclass == Object
|
@@ -204,21 +201,25 @@ module Neo4j
|
|
204
201
|
else
|
205
202
|
label.create_index(property) unless existing.flatten.include?(property)
|
206
203
|
end
|
207
|
-
|
208
204
|
end
|
209
205
|
end
|
210
206
|
|
211
207
|
def mapped_labels
|
212
|
-
mapped_label_names.map{|label_name| Neo4j::Label.create(label_name)}
|
208
|
+
mapped_label_names.map { |label_name| Neo4j::Label.create(label_name) }
|
213
209
|
end
|
214
210
|
|
215
|
-
def
|
216
|
-
@
|
211
|
+
def mapped_label_name=(name)
|
212
|
+
@mapped_label_name = name.to_sym
|
217
213
|
end
|
218
214
|
|
219
|
-
|
215
|
+
# rubocop:disable Style/AccessorMethodName
|
216
|
+
def set_mapped_label_name(name)
|
217
|
+
ActiveSupport::Deprecation.warn 'set_mapped_label_name is deprecated and may be removed from future releases, use self.mapped_label_name= instead.', caller
|
220
218
|
|
219
|
+
self.mapped_label_name = name
|
220
|
+
end
|
221
|
+
# rubocop:enable Style/AccessorMethodName
|
222
|
+
end
|
221
223
|
end
|
222
|
-
|
223
224
|
end
|
224
225
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class Neo4j::Node
|
2
2
|
# The wrapping process is what transforms a raw CypherNode or EmbeddedNode from Neo4j::Core into a healthy ActiveNode (or ActiveRel) object.
|
3
3
|
module Wrapper
|
4
|
-
|
5
4
|
# this is a plugin in the neo4j-core so that the Ruby wrapper will be wrapped around the Neo4j::Node objects
|
6
5
|
def wrapper
|
7
6
|
self.props.symbolize_keys!
|
@@ -26,22 +25,20 @@ class Neo4j::Node
|
|
26
25
|
|
27
26
|
# Makes the determination of whether to use <tt>_classname</tt> (or whatever is defined by config) or the node's labels.
|
28
27
|
def sorted_wrapper_classes
|
29
|
-
if self.props.is_a?(Hash) && self.props.
|
28
|
+
if self.props.is_a?(Hash) && self.props.key?(Neo4j::Config.class_name_property)
|
30
29
|
self.props[Neo4j::Config.class_name_property].constantize
|
31
30
|
else
|
32
31
|
wrappers = _class_wrappers
|
33
32
|
return self if wrappers.nil?
|
34
|
-
wrapper_classes = wrappers.map{|w| Neo4j::ActiveNode::Labels._wrapped_labels[w]}
|
33
|
+
wrapper_classes = wrappers.map { |w| Neo4j::ActiveNode::Labels._wrapped_labels[w] }
|
35
34
|
wrapper_classes.sort.first
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
38
|
def load_class_from_label(label_name)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
nil
|
44
|
-
end
|
39
|
+
label_name.to_s.split('::').inject(Kernel) { |container, name| container.const_get(name.to_s) }
|
40
|
+
rescue NameError
|
41
|
+
nil
|
45
42
|
end
|
46
43
|
|
47
44
|
def _class_wrappers
|