# # This file is part of the lazier gem. Copyright (C) 2013 and above Shogun . # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit. # # PI: Ignore flog on this file. require(RUBY_ENGINE != "jruby" ? "oj" : "json") require "English" require "tzinfo" require "active_support" require "active_support/core_ext" require "i18n" require "i18n/backend/fallbacks" require "hashie" require "pathname" I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) require "lazier/version" unless defined?(Lazier::Version) require "lazier/exceptions" require "lazier/i18n" require "lazier/configuration" require "lazier/settings" require "lazier/object" require "lazier/boolean" require "lazier/string" require "lazier/hash" require "lazier/datetime" require "lazier/timezone" require "lazier/math" require "lazier/pathname" # Several Ruby object enhancements. module Lazier # The root directory of the library ROOT = File.absolute_path(__dir__ + "/../") # Returns the settings for the extensions. # # @return [Settings] The settings for the extensions. def self.settings ::Lazier::Settings.instance end # Loads the extensions. # # @param what [Array] The modules to load. Valid values are: # @option object Extensions for all objects. # @option boolean Extensions for boolean values. # @option string Extensions for strings. # @option hash Extensions for hashs. # @option hash_method_access Extensions for hash to allow method access. Not included by default. # @option datetime Extensions date and time objects. # @option math Extensions for Math module. # @option pathname Extensions for path objects. # @return [Settings] The settings for the extensions. def self.load!(*what) valid_modules = [:object, :boolean, :string, :hash, :datetime, :math, :pathname] modules = what.present? ? what.flatten.uniq.compact.map(&:to_sym) : valid_modules (modules & valid_modules).each { |w| ::Lazier.send("load_#{w}") } yield if block_given? ::Lazier::Settings.instance end # Loads `Object` extensions. def self.load_object Lazier.load_boolean perform_load(:object, ::Object, ::Lazier::Object) end # Loads `Boolean` extensions. def self.load_boolean perform_load(:boolean) do [::TrueClass, ::FalseClass].each do |klass| klass.class_eval do include ::Lazier::Object include ::Lazier::Boolean end end end end # Loads `String` extensions. def self.load_string perform_load(:string, ::String, ::Lazier::String) end # Loads `Hash` extensions. def self.load_hash Lazier.load_object perform_load(:hash) do clean_hash_compact ::Hash.class_eval { include ::Lazier::Hash } end end # Loads `DateTime` extensions. def self.load_datetime Lazier.load_object perform_load(:datetime) do [::Time, ::Date, ::DateTime].each do |c| c.class_eval { include ::Lazier::DateTime } end ::ActiveSupport::TimeZone.class_eval { include ::Lazier::TimeZone } end end # Loads `Math` extensions. def self.load_math Lazier.load_object perform_load(:math, ::Math, ::Lazier::Math) end # Loads `Pathname` extensions. def self.load_pathname perform_load(:pathname, ::Pathname, ::Lazier::Pathname) end # Returns the list of loaded Lazier modules. # # @return [Array] The list of loaded Lazier modules. def self.loaded_modules @loaded || [] end # Checks if *all* of the specified modules have been loaded. # # @return [Boolean] `true` if the *all* of the specified modules has already been loaded, `false` otherwise. def self.modules_loaded?(*modules) (modules.flatten.uniq.compact.map(&:to_sym) - @loaded).blank? end # Finds a class to instantiate. # # @param cls [Symbol|String|Object] If a `String` or a `Symbol` or a `Class`, then it will be the class to instantiate. # Otherwise the class of the object will returned. # @param scope [String] The scope where to find the class. `%CLASS%`, `%`, `$`, `?` and `@` will be substituted with the class name. # @param only_in_scope [Boolean] If only search inside the scope. # @return [Class] The found class. def self.find_class(cls, scope = "::@", only_in_scope = false) if [::String, ::Symbol].include?(cls.class) cls = cls.to_s.camelize cls.gsub!(/^::/, "") if scope && only_in_scope search_class(cls, scope) || raise(NameError, ["", cls]) else cls.is_a?(::Class) ? cls : cls.class end end # Measure the time in milliseconds required to execute the given block. # # @param message [String|NilClass] An optional message (see return value). # @param precision [Fixnum] The precision for the message (see return value). # @param block [Proc] The block to evaluate. # @return [Float|String] If a `message` is provided, then the message itself plus the duration under parenthesis will be returned, # otherwise the duration alone as a number. def self.benchmark(message: nil, precision: 0, &block) rv = Benchmark.ms(&block) message ? format("%s (%0.#{precision}f ms)", message, rv) : rv end # Returns which platform are we running on. Can be `:java`, `:osx`, `:posix` or `:win32` # # @return [Boolean] If force detection again. # @return [Symbol] The current platform. def self.platform(force = false) @platform = nil if force @platform ||= case RUBY_PLATFORM when /cygwin|mingw|win32/ then :win32 when /java/ then :java when /darwin/ then :osx else :posix end end # :nodoc: def self.clean_hash_compact ::Hash.class_eval do remove_method(:compact) if {}.respond_to?(:compact) remove_method(:compact!) if {}.respond_to?(:compact!) end end # :nodoc: def self.search_class(cls, scope = nil) cls = scope.gsub(/%CLASS%|[@%$?]/, cls) cls.constantize rescue nil end # :nodoc: def self.perform_load(mod, target = nil, extension = nil, &block) @loaded ||= [] unless @loaded.include?(mod) block_given? ? block.call : target.class_eval { include extension } @loaded << mod end end end