module JSI
module Util::Private
autoload :AttrStruct, 'jsi/util/private/attr_struct'
autoload :MemoMap, 'jsi/util/private/memo_map'
extend self
EMPTY_ARY = [].freeze
EMPTY_SET = Set[].freeze
CLASSES_ALWAYS_FROZEN = Set[TrueClass, FalseClass, NilClass, Integer, Float, BigDecimal, Rational, Symbol].freeze
LAST_ARGUMENT_AS_KEYWORD_PARAMETERS = begin
if Object.const_defined?(:Warning)
warn = ::Warning.instance_method(:warn)
::Warning.send(:remove_method, :warn)
::Warning.send(:define_method, :warn) { |*, **| }
end
-> (k: ) { k }[{k: nil}]
true
rescue ArgumentError
false
ensure
if Object.const_defined?(:Warning)
::Warning.send(:remove_method, :warn)
::Warning.send(:define_method, :warn, warn)
end
end
USE_TO_JSON_METHOD = Hash.new do |h, klass|
h[klass] = klass.method_defined?(:to_json) &&
klass.instance_method(:to_json).owner.name !~ /\AJSON:.*:GeneratorMethods\b/
end
RUBY_REJECT_NAME_CODEPOINTS = [
0..31, %q( !"#$%&'()*+,-./:;<=>?@[\\]^`{|}~).each_codepoint, 127..159, ].inject(Set[], &:merge).freeze
RUBY_REJECT_NAME_RE = Regexp.new('[' + Regexp.escape(RUBY_REJECT_NAME_CODEPOINTS.to_a.pack('U*')) + ']+').freeze
def ok_ruby_method_name?(name)
return false unless name.respond_to?(:to_str)
return false if name =~ /\A[0-9]/
return false if name =~ RUBY_REJECT_NAME_RE
return true
end
def const_name_from_parts(parts, join: '')
parts = parts.map do |part|
part = part.dup
part[/\A[^a-zA-Z]*/] = ''
part[0] = part[0].upcase if part[0]
part.gsub!(RUBY_REJECT_NAME_RE, '_')
part
end
if !parts.all?(&:empty?)
parts.reject(&:empty?).join(join).freeze
else
nil
end
end
def uri(uri)
if uri.is_a?(Addressable::URI)
if uri.frozen?
uri
else
uri.dup.freeze
end
else
Addressable::URI.parse(uri).freeze
end
end
def ycomb
proc { |f| f.call(f) }.call(proc { |f| yield proc { |*x| f.call(f).call(*x) } })
end
def require_jmespath
return if instance_variable_defined?(:@jmespath_required)
begin
require 'jmespath'
rescue ::LoadError => e
msg = [
"please install and/or add to your Gemfile the `jmespath` gem to use this. jmespath is not a dependency of JSI.",
"original error message:",
e.message,
].join("\n")
raise(e.class, msg, e.backtrace)
end
hashlike = JSI::SchemaSet[].new_jsi({'test' => 0})
unless JMESPath.search('test', hashlike) == 0
raise(::LoadError, [
"the loaded version of jmespath cannot be used with JSI.",
"jmespath is compatible with JSI objects as of version 1.5.0",
].join("\n"))
end
@jmespath_required = true
nil
end
module FingerprintHash
def ==(other)
__id__ == other.__id__ || (other.is_a?(FingerprintHash) && jsi_fingerprint == other.jsi_fingerprint)
end
alias_method :eql?, :==
def hash
jsi_fingerprint.hash
end
end
module FingerprintHash::Immutable
include FingerprintHash
def ==(other)
return true if __id__ == other.__id__
return false unless other.is_a?(FingerprintHash)
return false if other.is_a?(FingerprintHash::Immutable) && hash != other.hash
jsi_fingerprint == other.jsi_fingerprint
end
alias_method :eql?, :==
def hash
@jsi_fingerprint_hash ||= jsi_fingerprint.hash
end
def freeze
hash
super
end
end
module Virtual
class InstantiationError < StandardError
end
def initialize
raise(InstantiationError, "cannot instantiate virtual class #{self.class}")
end
def virtual_method
raise(Bug, "class #{self.class} must implement #{caller_locations.first.label}")
end
end
end
end