Module: JSI::Util

Extended by:
Util
Includes:
Private
Included in:
Typelike, Util
Defined in:
lib/jsi/util.rb

Overview

JSI::Util contains public utilities

Defined Under Namespace

Modules: Arraylike, Hashlike, Private

Constant Summary

Constants included from Private

Private::EMPTY_ARY, Private::EMPTY_SET, Private::LAST_ARGUMENT_AS_KEYWORD_PARAMETERS

Instance Method Summary collapse

Methods included from Private

#ok_ruby_method_name?, #require_jmespath, #ycomb

Instance Method Details

#as_json(object, *opt) ⇒ Array, ...

recursive method to express the given argument object in json-compatible types of Hash, Array, and basic types of String/boolean/numeric/nil. this will raise TypeError if an object is given that is not a type that seems to be expressable as json.

similar effect could be achieved by requiring 'json/add/core' and using #as_json, but I don't much care for how it represents classes that are not naturally expressable in JSON, and prefer not to load its monkey-patching.

Parameters:

  • object (Object)

    the object to be converted to jsonifiability

Returns:

  • (Array, Hash, String, Boolean, NilClass, Numeric)

    jsonifiable expression of param object

Raises:

  • (TypeError)

    when the object (or an object nested with a hash or array of object) cannot be expressed as json



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/jsi/util.rb', line 46

def as_json(object, *opt)
  if object.is_a?(JSI::Base)
    as_json(object.jsi_node_content, *opt)
  elsif object.respond_to?(:to_hash)
    (object.respond_to?(:map) ? object : object.to_hash).map do |k, v|
      unless k.is_a?(Symbol) || k.respond_to?(:to_str)
        raise(TypeError, "json object (hash) cannot be keyed with: #{k.pretty_inspect.chomp}")
      end
      {k.to_s => as_json(v, *opt)}
    end.inject({}, &:update)
  elsif object.respond_to?(:to_ary)
    (object.respond_to?(:map) ? object : object.to_ary).map { |e| as_json(e, *opt) }
  elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| object.is_a?(c) }
    object
  elsif object.is_a?(Symbol)
    object.to_s
  elsif object.is_a?(Set)
    as_json(object.to_a, *opt)
  elsif object.respond_to?(:as_json)
    as_json(object.as_json(*opt), *opt)
  else
    raise(TypeError, "cannot express object as json: #{object.pretty_inspect.chomp}")
  end
end

#deep_stringify_symbol_keys(object) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/jsi/util.rb', line 98

def deep_stringify_symbol_keys(object)
  if object.respond_to?(:to_hash)
    JSI::Util.modified_copy(object) do |hash|
      out = {}
      (hash.respond_to?(:each) ? hash : hash.to_hash).each do |k, v|
        out[k.is_a?(Symbol) ? k.to_s : deep_stringify_symbol_keys(k)] = deep_stringify_symbol_keys(v)
      end
      out
    end
  elsif object.respond_to?(:to_ary)
    JSI::Util.modified_copy(object) do |ary|
      (ary.respond_to?(:each) ? ary : ary.to_ary).map do |e|
        deep_stringify_symbol_keys(e)
      end
    end
  else
    object
  end
end

#ensure_module_set(modules) ⇒ Set

ensures the given param becomes a frozen Set of Modules. returns the param if it is already that, otherwise initializes and freezes such a Set.

Parameters:

  • modules (Set, Enumerable)

    the object to ensure becomes a frozen Set of Modules

Returns:

  • (Set)

    frozen Set containing the given modules

Raises:

  • (ArgumentError)

    when the modules param is not an Enumerable

  • (Schema::NotASchemaError)

    when the modules param contains objects which are not Schemas



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/jsi/util.rb', line 125

def ensure_module_set(modules)
  if modules.is_a?(Set) && modules.frozen?
    set = modules
  else
    set = Set.new(modules).freeze
  end
  not_modules = set.reject { |s| s.is_a?(Module) }
  if !not_modules.empty?
    raise(TypeError, [
      "ensure_module_set given non-Module objects:",
      *not_modules.map { |ns| ns.pretty_inspect.chomp },
    ].join("\n"))
  end

  set
end

#modified_copy(object) {|Object| ... } ⇒ object.class

yields the content of the given param object. for objects which have a #jsi_modified_copy method of their own (JSI::Base, JSI::MetaschemaNode) that method is invoked with the given block. otherwise the given object itself is yielded.

the given block must result in a modified copy of its block parameter (not destructively modifying the yielded content).

Yields:

  • (Object)

    the content of the given object. the block should result in a (nondestructively) modified copy of this.

Returns:

  • (object.class)

    modified copy of the given object



23
24
25
26
27
28
29
# File 'lib/jsi/util.rb', line 23

def modified_copy(object, &block)
  if object.respond_to?(:jsi_modified_copy)
    object.jsi_modified_copy(&block)
  else
    return yield(object)
  end
end

#stringify_symbol_keys(hashlike) ⇒ same class as the param `hash`, or Hash if the former cannot be done

a hash copied from the given hashlike, in which any symbol keys are converted to strings. behavior on collisions is undefined (but in the future could take a block like ActiveSupport::HashWithIndifferentAccess#update)

at the moment it is undefined whether the returned hash is the same instance as the hash param. if hash is already a hash which contains no symbol keys, this method MAY return that same instance. use #dup on the return if you need to ensure it is not the same instance as the argument instance.

Parameters:

  • hashlike (#to_hash)

    the hash from which to convert symbol keys to strings

Returns:

  • (same class as the param `hash`, or Hash if the former cannot be done)

    a hash(-like) instance containing no symbol keys



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/jsi/util.rb', line 85

def stringify_symbol_keys(hashlike)
  unless hashlike.respond_to?(:to_hash)
    raise(ArgumentError, "expected argument to be a hash; got #{hashlike.class.inspect}: #{hashlike.pretty_inspect.chomp}")
  end
  JSI::Util.modified_copy(hashlike) do |hash|
    out = {}
    hash.each do |k, v|
      out[k.is_a?(Symbol) ? k.to_s : k] = v
    end
    out
  end
end