robust_excel_ole 1.29 → 1.30
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.
- checksums.yaml +4 -4
- data/Changelog +8 -0
- data/docs/README_open.rdoc +8 -4
- data/lib/robust_excel_ole/address_tool.rb +0 -2
- data/lib/robust_excel_ole/bookstore.rb +1 -1
- data/lib/robust_excel_ole/excel.rb +5 -15
- data/lib/robust_excel_ole/general.rb +239 -223
- data/lib/robust_excel_ole/list_object.rb +5 -1
- data/lib/robust_excel_ole/range.rb +5 -1
- data/lib/robust_excel_ole/range_owners.rb +4 -71
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +26 -17
- data/lib/robust_excel_ole/worksheet.rb +72 -4
- data/spec/base_spec.rb +17 -15
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/general_spec.rb +3 -0
- data/spec/workbook_spec.rb +11 -11
- data/spec/workbook_specs/workbook_misc_spec.rb +30 -30
- data/spec/workbook_specs/workbook_open_spec.rb +11 -0
- data/spec/workbook_specs/workbook_unobtr_spec.rb +289 -109
- data/spec/worksheet_spec.rb +18 -18
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 468109a0884d48ed77c70d9681d0067453aadfbd7294c6b152fb6457141bb98d
|
4
|
+
data.tar.gz: 2527cdd343eefb7325c077204203e1893d8e32f00830a8a6591669aba7ad43ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5637d87926eef9515335fb075add5cf4810cf97229c762f2b182fbdad42cae99f128c6a2ee253acbf29362c49005d579944e283e875aff4785df5220a6f0bff6
|
7
|
+
data.tar.gz: 59f015190d12c0a0b3c7e8016e6dd81da74ae5b760e166d0044a5b04dab5d0fb0b8fa295d13f66a30861a71867c921c2352119957b0543caeb467ecd881b3223
|
data/Changelog
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [1.30] 2020-18-11
|
5
|
+
|
6
|
+
## [1.29] 2020-05-11
|
7
|
+
|
8
|
+
### Added
|
9
|
+
- Workbook.open can also take a Pathname object
|
10
|
+
- General#init_reo_for_win32ole
|
11
|
+
|
4
12
|
## [1.28] 2020-23-10
|
5
13
|
|
6
14
|
## [1.27] 2020-16-10
|
data/docs/README_open.rdoc
CHANGED
@@ -17,6 +17,11 @@ The semantics is similar to, e.g., +File.open+.
|
|
17
17
|
# do something
|
18
18
|
end
|
19
19
|
|
20
|
+
You can provide the filename as a string (as above) or as Pathname object.
|
21
|
+
|
22
|
+
pathname = Pathname('spec/data/workbook.xls')
|
23
|
+
workbook = Workbook.open(pathname)
|
24
|
+
|
20
25
|
The options are the following:
|
21
26
|
|
22
27
|
+:default+:: if the workbook was already open, then use the properties of this workbook.otherwise use the properties stated in +:default+
|
@@ -195,12 +200,11 @@ The method +unobtrusively+ enables the user to read or modify a workbook, no mat
|
|
195
200
|
|
196
201
|
Options are the following:
|
197
202
|
|
198
|
-
+:if_closed+:: the Excel instance in which to open the workbook, if it was closed (default: +:current+). (Note: this option works workbooks opened via RobustExcelOle only.)
|
199
|
-
|
200
203
|
+:read_only+:: Whether the workbook shall be forced to be open in ReadOnly mode
|
201
|
-
+:writable+:: Whether changes in the workbook shall be saved
|
202
|
-
|
204
|
+
+:writable+:: Whether changes in the workbook shall be saved and the workbook shall be opened in ReadOnly mode by default (i.e., when the workbook was not open before) (default: true)
|
203
205
|
+:keep_open+:: Whether the workbook shall be open after unobtrusively opening (default: false)
|
206
|
+
+:if_closed+:: the Excel instance in which to open the workbook, if it was closed (default: +:current+).
|
207
|
+
(Note: this option works workbooks opened via RobustExcelOle only.)
|
204
208
|
|
205
209
|
There are the class method and the instance method of +unobtrusively+. Here is an example of the class method:
|
206
210
|
|
@@ -15,6 +15,7 @@ module RobustExcelOle
|
|
15
15
|
# See https://docs.microsoft.com/en-us/office/vba/api/excel.application(object)#methods
|
16
16
|
|
17
17
|
class Excel < VbaObjects
|
18
|
+
|
18
19
|
attr_reader :ole_excel
|
19
20
|
attr_reader :properties
|
20
21
|
attr_reader :address_tool
|
@@ -684,21 +685,7 @@ module RobustExcelOle
|
|
684
685
|
# Win32API.new("user32","SetForegroundWindow","","I").call
|
685
686
|
# end
|
686
687
|
end
|
687
|
-
|
688
|
-
# returns the value of a range
|
689
|
-
# @param [String] name the name of a range
|
690
|
-
# @returns [Variant] the value of the range
|
691
|
-
def [] name
|
692
|
-
namevalue_glob(name)
|
693
|
-
end
|
694
|
-
|
695
|
-
# sets the value of a range
|
696
|
-
# @param [String] name the name of the range
|
697
|
-
# @param [Variant] value the contents of the range
|
698
|
-
def []=(name, value)
|
699
|
-
set_namevalue_glob(name, value)
|
700
|
-
end
|
701
|
-
|
688
|
+
|
702
689
|
# @private
|
703
690
|
# returns active workbook
|
704
691
|
def workbook
|
@@ -717,6 +704,9 @@ module RobustExcelOle
|
|
717
704
|
to_s
|
718
705
|
end
|
719
706
|
|
707
|
+
using ParentRefinement
|
708
|
+
using StringRefinement
|
709
|
+
|
720
710
|
# @private
|
721
711
|
def self.workbook_class
|
722
712
|
@workbook_class ||= begin
|
@@ -1,4 +1,240 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
# @private
|
5
|
+
module ToReoRefinement
|
6
|
+
|
7
|
+
refine WIN32OLE do
|
8
|
+
|
9
|
+
# type-lifting WIN32OLE objects to RobustExcelOle objects
|
10
|
+
def to_reo
|
11
|
+
General.class2method.each do |element|
|
12
|
+
classname = element.first.first
|
13
|
+
method = element.first.last
|
14
|
+
begin
|
15
|
+
self.send(method)
|
16
|
+
if classname == RobustExcelOle::Range && self.Rows.Count == 1 && self.Columns.Count == 1
|
17
|
+
return Cell.new(self, self.Parent)
|
18
|
+
else
|
19
|
+
return classname.new(self)
|
20
|
+
end
|
21
|
+
rescue
|
22
|
+
next
|
23
|
+
end
|
24
|
+
end
|
25
|
+
raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# @private
|
33
|
+
class WIN32OLE
|
34
|
+
|
35
|
+
include Enumerable
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# @private
|
40
|
+
module FindAllIndicesRefinement
|
41
|
+
|
42
|
+
refine Array do
|
43
|
+
|
44
|
+
def find_all_indices elem
|
45
|
+
found, index, result = -1, -1, []
|
46
|
+
while found
|
47
|
+
found = self[index+1..-1].index(elem)
|
48
|
+
if found
|
49
|
+
index = index + found + 1
|
50
|
+
result << index
|
51
|
+
end
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# @private
|
61
|
+
module StringRefinement
|
62
|
+
|
63
|
+
refine String do
|
64
|
+
|
65
|
+
def / path_part
|
66
|
+
if empty?
|
67
|
+
path_part
|
68
|
+
else
|
69
|
+
if path_part.nil? || path_part.empty?
|
70
|
+
self
|
71
|
+
else
|
72
|
+
begin
|
73
|
+
File.join self, path_part
|
74
|
+
rescue TypeError
|
75
|
+
raise TypeError, "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# taken from http://apidock.com/rails/ActiveSupport/Inflector/underscore
|
82
|
+
def underscore
|
83
|
+
word = gsub('::', '/')
|
84
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
85
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
86
|
+
word.tr!('-', '_')
|
87
|
+
word.downcase!
|
88
|
+
word
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete_multiple_underscores
|
92
|
+
word = self
|
93
|
+
while word.index('__') do
|
94
|
+
word.gsub!('__','_')
|
95
|
+
end
|
96
|
+
word
|
97
|
+
end
|
98
|
+
|
99
|
+
def replace_umlauts
|
100
|
+
word = self
|
101
|
+
word.gsub!('ä','ae')
|
102
|
+
word.gsub!('Ä','Ae')
|
103
|
+
word.gsub!('ö','oe')
|
104
|
+
word.gsub!('Ö','Oe')
|
105
|
+
word.gsub!('ü','ue')
|
106
|
+
word.gsub!('Ü','Ue')
|
107
|
+
#word.gsub!(/\x84/,'ae')
|
108
|
+
#word.gsub!(/\x8E/,'Ae')
|
109
|
+
#word.gsub!(/\x94/,'oe')
|
110
|
+
#word.gsub!(/\x99/,'Oe')
|
111
|
+
#word.gsub!(/\x81/,'ue')
|
112
|
+
#word.gsub!(/\x9A/,'Ue')
|
113
|
+
word
|
114
|
+
end
|
115
|
+
|
116
|
+
# taken from http://apidock.com/rails/ActiveSupport/Inflector/constantize
|
117
|
+
# File activesupport/lib/active_support/inflector/methods.rb, line 226
|
118
|
+
def constantize # (camel_cased_word)
|
119
|
+
names = split('::')
|
120
|
+
|
121
|
+
# Trigger a builtin NameError exception including the ill-formed constant in the message.
|
122
|
+
Object.const_get(self) if names.empty?
|
123
|
+
|
124
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
125
|
+
names.shift if names.size > 1 && names.first.empty?
|
126
|
+
|
127
|
+
names.inject(Object) do |constant, name|
|
128
|
+
if constant == Object
|
129
|
+
constant.const_get(name)
|
130
|
+
else
|
131
|
+
candidate = constant.const_get(name)
|
132
|
+
next candidate if constant.const_defined?(name)
|
133
|
+
next candidate unless Object.const_defined?(name)
|
134
|
+
|
135
|
+
# Go down the ancestors to check it it's owned
|
136
|
+
# directly before we reach Object or the end of ancestors.
|
137
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
138
|
+
break const if ancestor == Object
|
139
|
+
break ancestor if ancestor.const_defined?(name)
|
140
|
+
|
141
|
+
const
|
142
|
+
end
|
143
|
+
|
144
|
+
# owner is in Object, so raise
|
145
|
+
constant.const_get(name)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @private
|
153
|
+
module ParentRefinement
|
154
|
+
|
155
|
+
using StringRefinement
|
156
|
+
|
157
|
+
# taken from http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/Module.html#M000806
|
158
|
+
refine Module do
|
159
|
+
|
160
|
+
def parent_name
|
161
|
+
unless defined? @parent_name
|
162
|
+
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
|
163
|
+
end
|
164
|
+
@parent_name
|
165
|
+
end
|
166
|
+
|
167
|
+
def parent
|
168
|
+
parent_name ? parent_name.constantize : Object
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Integer
|
174
|
+
|
175
|
+
alias old_spaceship <=>
|
176
|
+
|
177
|
+
def <=> other
|
178
|
+
# p other
|
179
|
+
if other.is_a? Array
|
180
|
+
self <=> other.first
|
181
|
+
else
|
182
|
+
old_spaceship other
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
# @private
|
189
|
+
class Array
|
190
|
+
|
191
|
+
alias old_spaceship <=>
|
192
|
+
|
193
|
+
def <=> other
|
194
|
+
# p other
|
195
|
+
if other.is_a? Integer
|
196
|
+
self <=> [other]
|
197
|
+
else
|
198
|
+
old_spaceship other
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
=begin
|
206
|
+
# @private
|
207
|
+
module SpaceshipRefinement
|
208
|
+
|
209
|
+
refine Integer do
|
210
|
+
|
211
|
+
alias old_spaceship <=>
|
212
|
+
|
213
|
+
def <=> other
|
214
|
+
# p other
|
215
|
+
if other.is_a? Array
|
216
|
+
self <=> other.first
|
217
|
+
else
|
218
|
+
old_spaceship other
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
refine Array do
|
224
|
+
|
225
|
+
alias old_spaceship <=>
|
226
|
+
|
227
|
+
def <=> other
|
228
|
+
# p other
|
229
|
+
if other.is_a? Integer
|
230
|
+
self <=> [other]
|
231
|
+
else
|
232
|
+
old_spaceship other
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
=end
|
2
238
|
|
3
239
|
module General
|
4
240
|
|
@@ -39,7 +275,8 @@ module General
|
|
39
275
|
end
|
40
276
|
|
41
277
|
# @private
|
42
|
-
def absolute_path(file)
|
278
|
+
def absolute_path(file)
|
279
|
+
file = file.to_path if file.respond_to?(:to_path)
|
43
280
|
return file if file[0,2] == "//"
|
44
281
|
file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
|
45
282
|
file = File.expand_path(file)
|
@@ -76,6 +313,7 @@ module General
|
|
76
313
|
{RobustExcelOle::ListObject => :ListRows}]
|
77
314
|
end
|
78
315
|
|
316
|
+
using ToReoRefinement
|
79
317
|
|
80
318
|
# enable RobustExcelOle methods to Win32Ole objects
|
81
319
|
def init_reo_for_win32ole
|
@@ -160,228 +398,6 @@ class Pry
|
|
160
398
|
end
|
161
399
|
end
|
162
400
|
|
163
|
-
class Integer
|
164
|
-
|
165
|
-
alias old_spaceship <=>
|
166
|
-
|
167
|
-
def <=> other
|
168
|
-
# p other
|
169
|
-
if other.is_a? Array
|
170
|
-
self <=> other.first
|
171
|
-
else
|
172
|
-
old_spaceship other
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
177
|
-
|
178
|
-
# @private
|
179
|
-
class Array
|
180
|
-
|
181
|
-
alias old_spaceship <=>
|
182
|
-
|
183
|
-
def <=> other
|
184
|
-
# p other
|
185
|
-
if other.is_a? Integer
|
186
|
-
self <=> [other]
|
187
|
-
else
|
188
|
-
old_spaceship other
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def find_each_index find
|
193
|
-
found, index, q = -1, -1, []
|
194
|
-
while found
|
195
|
-
found = self[index+1..-1].index(find)
|
196
|
-
if found
|
197
|
-
index = index + found + 1
|
198
|
-
q << index
|
199
|
-
end
|
200
|
-
end
|
201
|
-
q
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
=begin
|
206
|
-
# @private
|
207
|
-
module RefinedSpaceship
|
208
|
-
|
209
|
-
refine Integer do
|
210
|
-
|
211
|
-
alias old_spaceship <=>
|
212
|
-
|
213
|
-
def <=> other
|
214
|
-
# p other
|
215
|
-
if other.is_a? Array
|
216
|
-
self <=> other.first
|
217
|
-
else
|
218
|
-
old_spaceship other
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
refine Array do
|
224
|
-
|
225
|
-
alias old_spaceship <=>
|
226
|
-
|
227
|
-
def <=> other
|
228
|
-
# p other
|
229
|
-
if other.is_a? Integer
|
230
|
-
self <=> [other]
|
231
|
-
else
|
232
|
-
old_spaceship other
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
=end
|
238
|
-
|
239
|
-
# @private
|
240
|
-
class Array
|
241
|
-
|
242
|
-
def find_all_indices elem
|
243
|
-
found, index, result = -1, -1, []
|
244
|
-
while found
|
245
|
-
found = self[index+1..-1].index(elem)
|
246
|
-
if found
|
247
|
-
index = index + found + 1
|
248
|
-
result << index
|
249
|
-
end
|
250
|
-
end
|
251
|
-
result
|
252
|
-
end
|
253
|
-
|
254
|
-
end
|
255
|
-
|
256
|
-
# @private
|
257
|
-
class WIN32OLE
|
258
|
-
|
259
|
-
include Enumerable
|
260
|
-
|
261
|
-
# type-lifting WIN32OLE objects to RobustExcelOle objects
|
262
|
-
def to_reo
|
263
|
-
General.class2method.each do |element|
|
264
|
-
classname = element.first.first
|
265
|
-
method = element.first.last
|
266
|
-
begin
|
267
|
-
self.send(method)
|
268
|
-
if classname == RobustExcelOle::Range && self.Rows.Count == 1 && self.Columns.Count == 1
|
269
|
-
return Cell.new(self, self.Parent)
|
270
|
-
else
|
271
|
-
return classname.new(self)
|
272
|
-
end
|
273
|
-
rescue
|
274
|
-
next
|
275
|
-
end
|
276
|
-
end
|
277
|
-
raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
278
|
-
end
|
279
|
-
|
280
|
-
end
|
281
|
-
|
282
|
-
# @private
|
283
|
-
class ::String
|
284
|
-
def / path_part
|
285
|
-
if empty?
|
286
|
-
path_part
|
287
|
-
else
|
288
|
-
if path_part.nil? || path_part.empty?
|
289
|
-
self
|
290
|
-
else
|
291
|
-
begin
|
292
|
-
File.join self, path_part
|
293
|
-
rescue TypeError
|
294
|
-
raise TypeError, "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
# taken from http://apidock.com/rails/ActiveSupport/Inflector/underscore
|
301
|
-
def underscore
|
302
|
-
word = gsub('::', '/')
|
303
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
304
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
305
|
-
word.tr!('-', '_')
|
306
|
-
word.downcase!
|
307
|
-
word
|
308
|
-
end
|
309
|
-
|
310
|
-
def delete_multiple_underscores
|
311
|
-
word = self
|
312
|
-
while word.index('__') do
|
313
|
-
word.gsub!('__','_')
|
314
|
-
end
|
315
|
-
word
|
316
|
-
end
|
317
|
-
|
318
|
-
def replace_umlauts
|
319
|
-
word = self
|
320
|
-
word.gsub!('ä','ae')
|
321
|
-
word.gsub!('Ä','Ae')
|
322
|
-
word.gsub!('ö','oe')
|
323
|
-
word.gsub!('Ö','Oe')
|
324
|
-
word.gsub!('ü','ue')
|
325
|
-
word.gsub!('Ü','Ue')
|
326
|
-
#word.gsub!(/\x84/,'ae')
|
327
|
-
#word.gsub!(/\x8E/,'Ae')
|
328
|
-
#word.gsub!(/\x94/,'oe')
|
329
|
-
#word.gsub!(/\x99/,'Oe')
|
330
|
-
#word.gsub!(/\x81/,'ue')
|
331
|
-
#word.gsub!(/\x9A/,'Ue')
|
332
|
-
word
|
333
|
-
end
|
334
|
-
|
335
|
-
# taken from http://apidock.com/rails/ActiveSupport/Inflector/constantize
|
336
|
-
# File activesupport/lib/active_support/inflector/methods.rb, line 226
|
337
|
-
def constantize # (camel_cased_word)
|
338
|
-
names = split('::')
|
339
|
-
|
340
|
-
# Trigger a builtin NameError exception including the ill-formed constant in the message.
|
341
|
-
Object.const_get(self) if names.empty?
|
342
|
-
|
343
|
-
# Remove the first blank element in case of '::ClassName' notation.
|
344
|
-
names.shift if names.size > 1 && names.first.empty?
|
345
|
-
|
346
|
-
names.inject(Object) do |constant, name|
|
347
|
-
if constant == Object
|
348
|
-
constant.const_get(name)
|
349
|
-
else
|
350
|
-
candidate = constant.const_get(name)
|
351
|
-
next candidate if constant.const_defined?(name)
|
352
|
-
next candidate unless Object.const_defined?(name)
|
353
|
-
|
354
|
-
# Go down the ancestors to check it it's owned
|
355
|
-
# directly before we reach Object or the end of ancestors.
|
356
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
357
|
-
break const if ancestor == Object
|
358
|
-
break ancestor if ancestor.const_defined?(name)
|
359
|
-
|
360
|
-
const
|
361
|
-
end
|
362
|
-
|
363
|
-
# owner is in Object, so raise
|
364
|
-
constant.const_get(name)
|
365
|
-
end
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
|
-
|
370
|
-
# taken from http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/Module.html#M000806
|
371
|
-
# @private
|
372
|
-
class Module
|
373
|
-
def parent_name
|
374
|
-
unless defined? @parent_name
|
375
|
-
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
|
376
|
-
end
|
377
|
-
@parent_name
|
378
|
-
end
|
379
|
-
|
380
|
-
def parent
|
381
|
-
parent_name ? parent_name.constantize : Object
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
401
|
module MethodHelpers
|
386
402
|
|
387
403
|
# @private
|