class SubObject
Parent class for SubString and SubObject::SubArray
or similar.
Summary¶ ↑
This class SubObject
is the parent class for SubString and alike. This class expresses Ruby sub-Object (like Sub-String), which are obtained with the +self[i, j]+ method, but taking up negligible memory space, as its instance internally holds the (likely positional, though arbitrary) information +(i, j)+ only. It provides the basic interface so the instance behaves exactly like the original class (String for SubString, for example) as duck-typing, except destructive modification, which is prohibited.
If the original object is destructively modified in a way it changes its hash value, warning is issued whenever this instance is accessed.
Important note to the developers¶ ↑
To inherit this class, make sure to include the lines equivalent to the following 2 lines, replacing the method name :to_str
(which is for SubString class) to suit your child class.
TO_SOURCE_METHOD = :to_str alias_method TO_SOURCE_METHOD, :to_source
The full reference is found in the top page SubObject and in Github
@author Masa Sakano (Wise Babel Ltd)
Constants
- DESTRUCTIVE_METHODS
List of the names (String) of destructive methods (other than those ending with “!”).
- ERR_MSGS
Warning/Error messages.
- TO_SOURCE_METHOD
Symbol of the method that projects to (returns) the original-like instance; e.g., :to_str for String. The value should be overwritten in the child class of {SubObject}.
Attributes
Setter/Getter of the attribute. nil in default.
Starting (character) position
Public Class Methods
Returns a new instance of SubObject
equivalent to source[ pos, size ]
@param source [Object] source Object @param pos [Integer, Object] The first index for the method #[]
, usually the starting index position. @param size [Integer, Object] The second index for the method #[]
, usually the size. @param attr: [Object] user-specified arbitrary object
# File lib/sub_object.rb, line 92 def initialize(source, pos, size, attr: nil) @source, @pos, @isize = source, pos, size @attr = attr # Sanity check begin _ = @source[@pos, @isize] rescue NoMethodError raise TypeError, ERR_MSGS[:no_method_error] rescue ArgumentError raise TypeError, ERR_MSGS[:argument_error] rescue TypeError raise TypeError, ERR_MSGS[:type_error]%[pos.inspect, size.inspect] end if !source.respond_to? self.class::TO_SOURCE_METHOD raise TypeError, "Wrong source class #{source.class.name} for this class #{self.class.name}" end # Hash value retained to check its potential destructive change @hash = @source.hash end
Getter of the class instance variable @verbosity
# File lib/sub_object.rb, line 60 def self.verbose (defined? @verbosity) ? @verbosity : nil end
Setter of the class instance variable @@verbosity
# File lib/sub_object.rb, line 65 def self.verbose=(obj) @verbosity=obj end
Public Instance Methods
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 175 def <=>( *rest); to_source.send(__method__, *rest); end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 165 def ==( *rest); to_source.send(__method__, *rest); end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 167 def ===( *rest); to_source.send(__method__, *rest); end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 173 def =~( *rest); to_source.send(__method__, *rest); end
@return [String]
# File lib/sub_object.rb, line 182 def inspect warn_hash sprintf('%s[%d,%d]%s', self.class.name.split(/::/)[-1], @pos, @isize, @source[@pos, @isize].inspect) end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 169 def is_a?( *rest); to_source.send(__method__, *rest); end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 171 def kind_of?(*rest); to_source.send(__method__, *rest); end
method_missing
for any but destructive methods
@return [Object] @see respond_to_missing?
# File lib/sub_object.rb, line 191 def method_missing(method_name, *rest, &block) destructive_method?(method_name) ? super : to_source.send(method_name, *rest, &block) end
@return [Aray]
# File lib/sub_object.rb, line 116 def pos_size [@pos, @isize] end
Obligatory redefinition, following redefined {#method_missing}
# File lib/sub_object.rb, line 196 def respond_to_missing?(method_name, *rest) destructive_method?(method_name) ? super : to_source.send(:respond_to?, method_name, *rest) end
Frozen String returned.
# File lib/sub_object.rb, line 126 def source warn_hash src = @source.dup src.freeze src end
@return usually the size (Integer)
# File lib/sub_object.rb, line 121 def subsize @isize end
Redefining a method in Object to evaluate via {#to_source}
# File lib/sub_object.rb, line 177 def to_s( *rest); to_source.send(__method__, *rest); end
Returns the original representation of the instance as in the source
Each child class should set the constant TO_SOURCE_METHOD
appropriately and should alias this method to the method registered to TO_SOURCE_METHOD
. For example, for SubString,
TO_SOURCE_METHOD = :to_str alias_method TO_SOURCE_METHOD, :to_source
Warning: DO NOT OVERWRITE THIS METHOD.
@return [Object]
# File lib/sub_object.rb, line 145 def to_source warn_hash @source[@pos, @isize].send(to_source_method) end
Private Instance Methods
# File lib/sub_object.rb, line 204 def destructive_method?(method_name) met = method_name.to_s (/!$/ =~ met) || DESTRUCTIVE_METHODS.include?(met) end
Symbol of the method to get the original-like instance; e.g., :to_str for String. The value should be set in the child class, along with the crucial alias, e.g.,
TO_SOURCE_METHOD = :to_str alias_method TO_SOURCE_METHOD, :to_source
@return [Symbol] Method name like :to_str
# File lib/sub_object.rb, line 54 def to_source_method self.class::TO_SOURCE_METHOD end
# File lib/sub_object.rb, line 210 def warn_hash klass = self.class verbosity_loc = (klass.instance_variable_defined?(:@verbosity) ? klass.instance_variable_get(:@verbosity) : nil) if ((verbosity_loc.nil? && !$VERBOSE.nil?) || verbosity_loc) && @hash != @source.hash str = @source[@pos, @isize].inspect # Suppresses the length only for warning (not the standard inspect), which would be printed repeatedly. str = str[0,60]+'..."' if str.size > 64 # warn() would not run if $VERBOSE.nil? (in this case it should run if @verbosity is true). $stderr.printf("WARNING: source string has destructively changed: %s[%d,%d]%s\n", self.class.name, @pos, @isize, str) end end