Module: Foobara::Util
- Defined in:
- foobara-util-0.0.11/lib/foobara/util/args.rb,
foobara-util-0.0.11/lib/foobara/util/hash.rb,
foobara-util-0.0.11/lib/foobara/util/meta.rb,
foobara-util-0.0.11/lib/foobara/util/tree.rb,
foobara-util-0.0.11/lib/foobara/util/array.rb,
foobara-util-0.0.11/lib/foobara/util/class.rb,
foobara-util-0.0.11/lib/foobara/util/module.rb,
foobara-util-0.0.11/lib/foobara/util/string.rb,
foobara-util-0.0.11/lib/foobara/util/require.rb,
foobara-util-0.0.11/lib/foobara/util/structured.rb
Defined Under Namespace
Classes: ParentModuleDoesNotExistError, SubTree, Tree
Constant Summary collapse
- IS_CAP =
/[A-Z]/
- IS_IDENTIFIER_CHARACTER =
/\w/
Class Method Summary collapse
- .all_blank_or_false?(array) ⇒ Boolean
- .all_symbolic_elements?(array) ⇒ Boolean
- .all_symbolic_keys?(hash) ⇒ Boolean
- .all_symbolizable_elements?(array) ⇒ Boolean
- .all_symbolizable_keys?(hash) ⇒ Boolean
- .arg_and_opts_to_arg(arg, opts) ⇒ Object
-
.args_and_opts_to_args(args, opts) ⇒ Object
Strange utility method here…
- .args_and_opts_to_opts(args, opts) ⇒ Object
- .array(object) ⇒ Object
- .camelize(string, upcase_first = false) ⇒ Object
- .classify(string) ⇒ Object
- .const_get_up_hierarchy(mod, name) ⇒ Object
- .constant_value(mod, constant, inherit: false) ⇒ Object
- .constant_values(mod, is_a: nil, extends: nil, inherit: false) ⇒ Object
- .constantify(string) ⇒ Object
- .constantify_sym(string) ⇒ Object
- .deep_dup(object) ⇒ Object
- .deep_stringify_keys(object) ⇒ Object
- .descendants(klass) ⇒ Object
- .find_constant_through_class_hierarchy(klass, constant) ⇒ Object
- .humanize(string) ⇒ Object
-
.instances(klass) ⇒ Object
WARNING: This approach is known as being slow.
- .kebab_case(string) ⇒ Object
- .make_class(name, superclass = nil, which: :class, tag: false, &block) ⇒ Object
- .make_class_p(name, superclass = nil, which: :class, tag: false) ⇒ Object
-
.make_module(name) ⇒ Object
TODO: Kind of weird that make_module is implemented in terms of make_class instead of the other way around.
- .make_module_p(name, tag: false) ⇒ Object
- .module_for(mod) ⇒ Object
- .non_full_name(mod) ⇒ Object
- .non_full_name_underscore(mod) ⇒ Object
- .parent_module_name_for(module_name) ⇒ Object
- .power_set(array) ⇒ Object
- .print_tree(data, io: $stdout, to_name: nil, to_parent: nil) ⇒ Object
- .remove_blank(hash) ⇒ Object
- .remove_constant(const_name) ⇒ Object
- .remove_empty(hash) ⇒ Object
- .require_directory(directory) ⇒ Object
- .require_pattern(glob) ⇒ Object
-
.super_method_of(current_instance, from_class, method_name) ⇒ Object
Kind of surprising that Ruby doesn’t have a built in way to do this.
- .super_method_takes_parameters?(current_instance, from_class, method_name) ⇒ Boolean
- .symbolize_keys(hash) ⇒ Object
- .symbolize_keys!(hash) ⇒ Object
- .to_or_sentence(strings, connector = ", ") ⇒ Object
- .to_sentence(strings, connector = ", ", last_connector = ", and ") ⇒ Object
- .underscore(string) ⇒ Object
- .underscore_sym(string) ⇒ Object
Class Method Details
.all_blank_or_false?(array) ⇒ Boolean
32 33 34 35 36 37 38 |
# File 'foobara-util-0.0.11/lib/foobara/util/array.rb', line 32 def all_blank_or_false?(array) array.all? do |element| element.nil? || element == false || ( (element.is_a?(::Hash) || element.is_a?(::Array) || element.is_a?(::String)) && element.empty? ) end end |
.all_symbolic_elements?(array) ⇒ Boolean
24 25 26 |
# File 'foobara-util-0.0.11/lib/foobara/util/array.rb', line 24 def all_symbolic_elements?(array) array.all? { |key| key.is_a?(Symbol) || key.is_a?(String) } end |
.all_symbolic_keys?(hash) ⇒ Boolean
25 26 27 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 25 def all_symbolic_keys?(hash) all_symbolic_elements?(hash.keys) end |
.all_symbolizable_elements?(array) ⇒ Boolean
28 29 30 |
# File 'foobara-util-0.0.11/lib/foobara/util/array.rb', line 28 def all_symbolizable_elements?(array) array.all? { |key| key.is_a?(Symbol) || key.is_a?(String) } end |
.all_symbolizable_keys?(hash) ⇒ Boolean
29 30 31 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 29 def all_symbolizable_keys?(hash) all_symbolizable_elements?(hash.keys) end |
.arg_and_opts_to_arg(arg, opts) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'foobara-util-0.0.11/lib/foobara/util/args.rb', line 42 def arg_and_opts_to_arg(arg, opts) if arg && !arg.empty? if opts && !opts.empty? unless opts.is_a?(::Hash) # :nocov: raise ArgumentError, "opts must be a hash not a #{opts}" # :nocov: end unless arg.is_a?(::Hash) # :nocov: raise ArgumentError, "arg must be a hash if present when opts is present" # :nocov: end arg.merge(opts) else arg end elsif opts && !opts.empty? opts end end |
.args_and_opts_to_args(args, opts) ⇒ Object
Strange utility method here… idea is there’s a method that takes 0 or 1 arguments which may or may not be a hash. To make sure we don’t act like there’s an argument when there’s not or fail to combine parts of the hash that wind up in opts, this method comines it into an array of 0 or 1 argument with stuff merged into the argument if needed.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'foobara-util-0.0.11/lib/foobara/util/args.rb', line 71 def args_and_opts_to_args(args, opts) unless args.is_a?(::Array) # :nocov: raise ArgumentError, "args must be an array of 0 or 1 hashes but received #{args}" # :nocov: end case args.size when 0 Util.array(arg_and_opts_to_arg(nil, opts)) when 1 # Do not go from 1 argument to 0. ie, [nil] should return [nil] not []. if opts && !opts.empty? arg = args.first unless arg.is_a?(::Hash) # :nocov: raise ArgumentError, "Expected #{arg.inspect} to be a Hash" # :nocov: end [arg_and_opts_to_arg(args.first, opts)] else args end [arg_and_opts_to_arg(args.first, opts)] else # :nocov: raise ArgumentError, "args must be an array of 0 or 1 hashes but received #{args}" # :nocov: end end |
.args_and_opts_to_opts(args, opts) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'foobara-util-0.0.11/lib/foobara/util/args.rb', line 5 def args_and_opts_to_opts(args, opts) unless args.is_a?(::Array) # :nocov: raise ArgumentError, "args must be an array of 0 or 1 hashes but received #{args}" # :nocov: end unless opts.is_a?(::Hash) # :nocov: raise ArgumentError, "opts must be a hash not a #{opts.class}" # :nocov: end case args.size when 0 opts when 1 arg = args.first if opts && !opts.empty? unless arg.is_a?(::Hash) # :nocov: raise ArgumentError, "opts must be a hash not a #{arg.class}" # :nocov: end arg.merge(opts) else arg end else # :nocov: raise ArgumentError, "args must be an array of 0 or 1 hashes but received #{args}" # :nocov: end end |
.array(object) ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'foobara-util-0.0.11/lib/foobara/util/array.rb', line 13 def array(object) case object when nil [] when Array object else [object] end end |
.camelize(string, upcase_first = false) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 9 def camelize(string, upcase_first = false) return nil if string.nil? if string.is_a?(::Symbol) string = string.to_s end retval = "" string.each_char do |char| if ["_", "-"].include?(char) upcase_first = true elsif upcase_first retval << char.upcase upcase_first = false else retval << char.downcase end end retval end |
.classify(string) ⇒ Object
5 6 7 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 5 def classify(string) camelize(string, true) end |
.const_get_up_hierarchy(mod, name) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 69 def const_get_up_hierarchy(mod, name) mod.const_get(name) rescue NameError => e if mod == Object || e. !~ /uninitialized constant (.*::)?#{name}\z/ # :nocov: raise # :nocov: end mod = if mod.name&.include?("::") module_for(mod) else Object end const_get_up_hierarchy(mod, name) end |
.constant_value(mod, constant, inherit: false) ⇒ Object
32 33 34 35 36 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 32 def constant_value(mod, constant, inherit: false) if mod.constants(inherit).include?(constant.to_sym) mod.const_get(constant, inherit) end end |
.constant_values(mod, is_a: nil, extends: nil, inherit: false) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 38 def constant_values(mod, is_a: nil, extends: nil, inherit: false) if inherit && !mod.is_a?(Class) # :nocov: raise "Cannot pass inherit: true for something that is not a Class" # :nocov: end if inherit superklass = mod.superclass values = constant_values(mod, is_a:, extends:) if superklass == Object values else [ *values, *constant_values(superklass, is_a:, extends:, inherit:) ] end else is_a = Util.array(is_a) extends = Util.array(extends) mod.constants.map { |const| constant_value(mod, const) }.select do |object| (is_a.nil? || is_a.empty? || is_a.any? { |klass| object.is_a?(klass) }) && (extends.nil? || extends.empty? || (object.is_a?(Class) && extends.any? do |klass| object.ancestors.include?(klass) end)) end.compact end end |
.constantify(string) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 35 def constantify(string) return nil if string.nil? if string.is_a?(::Symbol) string = string.to_s end if string =~ /\A[A-Z_]*\z/ string.dup else underscore(string).upcase end end |
.constantify_sym(string) ⇒ Object
49 50 51 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 49 def constantify_sym(string) constantify(string)&.to_sym end |
.deep_dup(object) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'foobara-util-0.0.11/lib/foobara/util/structured.rb', line 18 def deep_dup(object) case object when ::Array object.map { |element| deep_dup(element) } when ::Hash object.to_h { |k, v| [deep_dup(k), deep_dup(v)] } when ::String # Important to not dup ::Module... but going to exclude everything but String for now to prevent that issue # and others. object.dup else object end end |
.deep_stringify_keys(object) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'foobara-util-0.0.11/lib/foobara/util/structured.rb', line 5 def deep_stringify_keys(object) case object when ::Array object.map { |element| deep_stringify_keys(element) } when ::Hash object.to_h do |k, v| [k.is_a?(::Symbol) ? k.to_s : k, deep_stringify_keys(v)] end else object end end |
.descendants(klass) ⇒ Object
5 6 7 8 9 10 11 12 13 14 |
# File 'foobara-util-0.0.11/lib/foobara/util/class.rb', line 5 def descendants(klass) all = Set.new klass.subclasses.each do |subclass| all << subclass all |= descendants(subclass) end all end |
.find_constant_through_class_hierarchy(klass, constant) ⇒ Object
33 34 35 36 37 38 39 |
# File 'foobara-util-0.0.11/lib/foobara/util/class.rb', line 33 def find_constant_through_class_hierarchy(klass, constant) if klass.const_defined?(constant) klass.const_get(constant) else find_constant_through_class_hierarchy(klass.superclass, constant) end end |
.humanize(string) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 112 def humanize(string) return nil if string.nil? if string.is_a?(::Symbol) string = string.to_s end return "" if string.empty? string = string.gsub("_", " ") string[0] = string[0].upcase string end |
.instances(klass) ⇒ Object
WARNING: This approach is known as being slow. Probably better for you class to track its own instances if this is being used for smoething more than debugging.
18 19 20 |
# File 'foobara-util-0.0.11/lib/foobara/util/class.rb', line 18 def instances(klass) ObjectSpace.each_object(klass).to_a end |
.kebab_case(string) ⇒ Object
88 89 90 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 88 def kebab_case(string) underscore(string)&.gsub("_", "-") end |
.make_class(name, superclass = nil, which: :class, tag: false, &block) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'foobara-util-0.0.11/lib/foobara/util/meta.rb', line 16 def make_class(name, superclass = nil, which: :class, tag: false, &block) name = name.to_s if name.is_a?(::Symbol) if superclass.is_a?(Class) superclass = superclass.name end inherit = superclass ? " < ::#{superclass}" : "" superclass ||= :Object name = name[2..] if name.start_with?("::") already_exists = Object.const_defined?(name, false) if !already_exists && tag should_tag = true end parent_name = parent_module_name_for(name) if parent_name && !Object.const_defined?(parent_name, false) raise ParentModuleDoesNotExistError.new(name:, parent_name:) end unless already_exists # rubocop:disable Security/Eval, Style/DocumentDynamicEvalDefinition eval(<<~RUBY, binding, __FILE__, __LINE__ + 1) #{which} ::#{name}#{inherit} end RUBY # rubocop:enable Security/Eval, Style/DocumentDynamicEvalDefinition end klass = Object.const_get(name, false) if should_tag klass.instance_variable_set(:@foobara_created_via_make_class, true) end if block if klass.is_a?(::Class) klass.class_eval(&block) else klass.module_eval(&block) end end klass end |
.make_class_p(name, superclass = nil, which: :class, tag: false) ⇒ Object
67 68 69 70 71 72 |
# File 'foobara-util-0.0.11/lib/foobara/util/meta.rb', line 67 def make_class_p(name, superclass = nil, which: :class, tag: false, &) make_class(name, superclass, which:, tag:, &) rescue ParentModuleDoesNotExistError => e make_class_p(e.parent_name, which: :module, tag:, &) make_class(name, superclass, which:, tag:, &) end |
.make_module(name) ⇒ Object
TODO: Kind of weird that make_module is implemented in terms of make_class instead of the other way around
75 76 77 |
# File 'foobara-util-0.0.11/lib/foobara/util/meta.rb', line 75 def make_module(name, &) make_class(name, which: :module, &) end |
.make_module_p(name, tag: false) ⇒ Object
79 80 81 |
# File 'foobara-util-0.0.11/lib/foobara/util/meta.rb', line 79 def make_module_p(name, tag: false, &) make_class_p(name, which: :module, tag:, &) end |
.module_for(mod) ⇒ Object
5 6 7 8 9 10 11 12 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 5 def module_for(mod) name = mod.name return unless name name = parent_module_name_for(mod.name) Object.const_get(name) if name end |
.non_full_name(mod) ⇒ Object
18 19 20 21 22 23 24 25 26 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 18 def non_full_name(mod) name = if mod.is_a?(::String) mod else mod.name end name&.[](/([^:]+)\z/, 1) end |
.non_full_name_underscore(mod) ⇒ Object
28 29 30 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 28 def non_full_name_underscore(mod) underscore(non_full_name(mod)) end |
.parent_module_name_for(module_name) ⇒ Object
14 15 16 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 14 def parent_module_name_for(module_name) module_name[/(.*)::/, 1] end |
.power_set(array) ⇒ Object
5 6 7 8 9 10 11 |
# File 'foobara-util-0.0.11/lib/foobara/util/array.rb', line 5 def power_set(array) return [[]] if array.empty? head, *tail = array subsets = power_set(tail) subsets + subsets.map { |subset| [head, *subset] } end |
.print_tree(data, io: $stdout, to_name: nil, to_parent: nil) ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'foobara-util-0.0.11/lib/foobara/util/tree.rb', line 128 def print_tree(data, io: $stdout, to_name: nil, to_parent: nil) data = data.to_a if data.is_a?(::Hash) if to_name.nil? && to_parent.nil? to_name = :first.to_proc to_parent = proc do |object| parent_name = object.last data.find { |pair| pair.first == parent_name } end end tree = Util::Tree.new(data, to_parent) io.puts tree.to_s(to_name) end |
.remove_blank(hash) ⇒ Object
37 38 39 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 37 def remove_blank(hash) remove_empty(hash).compact end |
.remove_constant(const_name) ⇒ Object
87 88 89 90 91 92 |
# File 'foobara-util-0.0.11/lib/foobara/util/module.rb', line 87 def remove_constant(const_name) *path, name = const_name.split("::") mod = path.inject(Object) { |m, constant| m.const_get(constant) } mod.send(:remove_const, name) end |
.remove_empty(hash) ⇒ Object
33 34 35 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 33 def remove_empty(hash) hash.reject { |_k, v| (v.is_a?(::Hash) || v.is_a?(::Array)) && v.empty? } end |
.require_directory(directory) ⇒ Object
5 6 7 |
# File 'foobara-util-0.0.11/lib/foobara/util/require.rb', line 5 def require_directory(directory) require_pattern("#{directory}/**/*.rb") end |
.require_pattern(glob) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'foobara-util-0.0.11/lib/foobara/util/require.rb', line 9 def require_pattern(glob) files = Dir[glob] if files.empty? # :nocov: raise "Didn't find anything to require for #{glob}" # :nocov: end files.sort_by { |file| [file.count("/"), file.length] }.reverse.each do |f| require f end end |
.super_method_of(current_instance, from_class, method_name) ⇒ Object
Kind of surprising that Ruby doesn’t have a built in way to do this.
23 24 25 26 27 |
# File 'foobara-util-0.0.11/lib/foobara/util/class.rb', line 23 def super_method_of(current_instance, from_class, method_name) method = current_instance.method(method_name) method = method.super_method until method.owner == from_class method.super_method end |
.super_method_takes_parameters?(current_instance, from_class, method_name) ⇒ Boolean
29 30 31 |
# File 'foobara-util-0.0.11/lib/foobara/util/class.rb', line 29 def super_method_takes_parameters?(current_instance, from_class, method_name) super_method_of(current_instance, from_class, method_name).parameters.any? end |
.symbolize_keys(hash) ⇒ Object
5 6 7 8 9 10 11 12 13 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 5 def symbolize_keys(hash) unless all_symbolizable_keys?(hash) # :nocov: raise "Cannot symbolize keys for #{hash} because they are not all symbolizable" # :nocov: end hash.transform_keys(&:to_sym) end |
.symbolize_keys!(hash) ⇒ Object
15 16 17 18 19 20 21 22 23 |
# File 'foobara-util-0.0.11/lib/foobara/util/hash.rb', line 15 def symbolize_keys!(hash) unless all_symbolizable_keys?(hash) # :nocov: raise "Cannot symbolize keys for #{hash} because they are not all symbolizable" # :nocov: end hash.transform_keys!(&:to_sym) end |
.to_or_sentence(strings, connector = ", ") ⇒ Object
108 109 110 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 108 def to_or_sentence(strings, connector = ", ") to_sentence(strings, connector, ", or ") end |
.to_sentence(strings, connector = ", ", last_connector = ", and ") ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 96 def to_sentence(strings, connector = ", ", last_connector = ", and ") return "" if strings.empty? *strings, last = strings if strings.empty? last else [strings.join(connector), last].join(last_connector) end end |
.underscore(string) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 53 def underscore(string) return nil if string.nil? if string.is_a?(::Symbol) string = string.to_s end return "" if string.empty? string = string.gsub(/[-.]/, "_") retval = "" is_start = true string.each_char do |char| if IS_IDENTIFIER_CHARACTER =~ char if IS_CAP =~ char char = char.downcase char = "_#{char}" unless is_start is_start = false elsif char == "_" is_start = true else is_start = false end else is_start = true end retval << char end retval end |
.underscore_sym(string) ⇒ Object
92 93 94 |
# File 'foobara-util-0.0.11/lib/foobara/util/string.rb', line 92 def underscore_sym(string) underscore(string)&.to_sym end |