./lib/overload/hash.rb in lux-fw-0.5.37 vs ./lib/overload/hash.rb in lux-fw-0.6.2

- old
+ new

@@ -1,121 +1,39 @@ -# frozen_string_literal: true - -require_relative '../common/free_struct' - class Hash - def h - Hashie::Mash.new(self) - end - - def h_wia - HashWithIndifferentAccess.new(self) - end - - # readonly hash with .to_h - def to_readonly name=nil - Class.new.tap do |c| - c.define_singleton_method(:to_h) do - m_list = methods(false) - [:to_h] - m_list.inject({}) do |h,m| - h[m] = send(m) - h[m] = h[m].to_h if h[m].class == Class - h - end - end - - each do |k, v| - v = v.to_readonly if v.class == Hash - c.define_singleton_method(k) { v } - end - end - end - - # {...}.to_opts :name, :age - # {...}.to_opts name: String, age: Integer - def to_opts *keys - if keys.first.is_a?(Hash) - # if given Hash check opt class types - keys.first.each do |key, target_class| - source = self[key] - - if target_class && !source.nil? && !source.is_a?(target_class) - raise ArgumentError.new(%[Expected argument :#{key} to be of type "#{target_class}" not "#{source.class}"]) - end - end - - keys = keys.first.keys - end - - not_allowed = self.keys - keys - raise ArgumentError.new('Key :%s not allowed in option' % not_allowed.first) if not_allowed.first - - FreeStruct.new keys.inject({}) { |total, key| - raise 'Hash key :%s is not allowed!' % key unless keys.include?(key) - total[key] = self[key] - total - } - end - - def to_struct - to_opts *keys - end - - def tag node=nil, text=nil - HtmlTagBuilder.build self, node, text - end - def blank? self.keys.count == 0 end def to_query namespace=nil - self.keys.sort.map { |k| + keys = self.keys.sort + + return unless keys.first + + '?' + keys.map do |k| name = namespace ? "#{namespace}[#{k}]" : k "#{name}=#{CGI::escape(self[k].to_s)}" - }.join('&') + end.join('&') end - def data_attributes - self.keys.sort.map{ |k| 'data-%s="%s"' % [k, self[k].to_s.gsub('"', '"')]}.join(' ') + def to_attributes + self.keys.sort.map{ |k| '%s="%s"' % [k, self[k].to_s.gsub('"', '"')]}.join(' ') end def pluck *args string_args = args.map(&:to_s) self.select{ |k,v| string_args.index(k.to_s) } end - def transform_keys - return enum_for(:transform_keys) unless block_given? - result = self.class.new - each_key do |key| - result[yield(key)] = self[key] - end - result + def stringify_keys + transform_keys { |key| key.to_s } end - def transform_keys! - return enum_for(:transform_keys!) unless block_given? - keys.each do |key| - self[yield(key)] = delete(key) - end - self - end - def symbolize_keys - transform_keys{ |key| key.to_sym rescue key } + transform_keys { |key| key.respond_to?(:to_sym) ? key.to_sym : key } end - def symbolize_keys! - transform_keys!{ |key| key.to_sym rescue key } - end - - def pretty_generate - JSON.pretty_generate(self).gsub(/"([\w\-]+)":/) { %["#{$1.yellow}":] } - end - - # Returns hash with only se + # Returns hash with only selected keys def slice *keys keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) } end @@ -140,10 +58,64 @@ dup.except!(*keys) end # Hash#except in place, modifying current hash def except!(*keys) - keys.each { |key| delete(key) } + keys.each { |key| delete(key.to_s); delete(key.to_sym) } self + end + + def remove_empty covert_to_s = false + self.keys.inject({}) do |t, el| + v = self[el] + t[covert_to_s ? el.to_s : el] = v if el.present? && v.present? + t + end + end + + def to_js opts = {} + data = opts[:empty] ? self : remove_empty + data = data.to_json.gsub(/"(\w+)":/, "\\1:") + data = data.gsub(/",(\w)/, '", \1') unless opts[:narrow] + data + end + + def transform_keys &block + if block + Hash.new.tap do |result| + for key, value in self + value = value.transform_keys(&block) if value.is_a?(Hash) + result[block.call(key)] = value + end + end + else + enum_for(:transform_keys) + end + end + + # clean empty values from hash, deep + def deep_compact value = nil + value ||= self + + res_hash = value.map do |key, value| + value = deep_compact(value) if value.is_a?(Hash) + + # we need to remove '0' because that is what empty checkbox inserts, but it is nil + value = nil if [{}, [], '0'].include?(value) + value = nil if value.blank? + [key, value] + end + + res_hash.to_h.compact + end + + def self.deep_compact value + (value || {}).deep_compact + end + + def html_safe key + if data = self[key] + self[key] = data.html_safe + end end end