lib/eco/language/models/collection.rb in eco-helpers-1.5.1 vs lib/eco/language/models/collection.rb in eco-helpers-1.5.2

- old
+ new

@@ -2,23 +2,23 @@ module Language module Models class Collection include Enumerable - ATTR_PRESENCE_METHODS = ["present", "empty", "present_all?", "present_some?"] - ATTR_COLLECTION_METHODS = ["exclude", "remove", "attr", "attr?", "attrs", "unique_attrs", "contains"] + ATTR_PRESENCE_METHODS + BASIC_METHODS = ["present", "empty", "present_all?", "present_some?"] + EXTENDED_METHODS = BASIC_METHODS + ["exclude", "remove", "attr", "attr?", "attrs", "unique_attrs", "contains"] class << self - def attr_collection (*attrs) + def attr_presence(*attrs) block = ->(method) { attrs_create_method(attrs, method) } - ATTR_COLLECTION_METHODS.each(&block) + BASIC_METHODS.each(&block) end - def attr_presence (*attrs) + def attr_collection(*attrs) block = ->(method) { attrs_create_method(attrs, method) } - ATTR_PRESENCE_METHODS.each(&block) + EXTENDED_METHODS.each(&block) end def attrs_create_method(attrs, method) attrs.each do |attr| attr = attr.to_s @@ -33,46 +33,45 @@ end end end - #attr_reader :items - def initialize(data = [], klass:, factory: nil, handy: Eco::Assets::Language.new) raise "Raise klass required, given: #{klass}" if !klass @klass = klass @factory = factory @handy = handy @items = to_klass(data) end + # @!group pure collection methods + def to_c + Collection.new(self, klass: @klass, factory: @factory) + end + + def new + newFrom to_a + end + def newFrom(data) self.class.new(data, klass: @klass, factory: @factory) end def merge(data) data = data.to_a unless data.is_a?(Array) newFrom to_a + data end - def to_c - Collection.new(self, klass: @klass, factory: @factory) - end - - def new - self.class.new(to_a, klass: @klass, factory: @factory) - end - def length count end def empty? count == 0 end - def each(params: {}, &block) + def each(&block) return to_enum(:each) unless block @items.each(&block) end def <(value) @@ -91,51 +90,61 @@ end def delete!(value) self < @items - into_a(value) end + # @!endgroup - # attr dependant methods - def exclude(attr, value, modifier = Language::MatchModifier.new) + # @!group `attr` dependant methods + def exclude(attr, value, modifier = default_modifier) newFrom @items - self.attr(attr, value, modifier) end - def remove(attr, value, modifier = Language::MatchModifier.new) + def remove(attr, value, modifier = default_modifier) self < exclude(attr, value, modifier) end - def attr(attr, value = true, modifier = Language::MatchModifier.new) - if !!value == value # boolean? - present(attr, value) - else - return newFrom select { |object| - attr_val = fetch_attr(object, attr) - match?(attr_val, value, modifier) - } + def attr(attr, value = true, modifier = default_modifier) + return present(attr, value) if boolean?(value) + select do |object| + match?(attr_value(object, attr), value, modifier) + end.yield_self do |matching| + newFrom matching end end - def attr?(attr, value = true, modifier = Language::MatchModifier.new) - modifier = modifier.new.reverse - if !!value == value # boolean? - present(attr, value).length == length - else - obj_vals = attrs(attr) - return match?(obj_vals, value, modifier) - end + def attr?(attr, value = true, modifier = default_modifier) + return present(attr, value).length == length if boolean?(value) + match?(attrs(attr), value, modifier.new.reverse) end + def contains(attr, value, modifier = default_modifier) + self.attr(attr, value, modifier.new.pattern) + end + def attrs(attr) - map { |object| fetch_attr(object, attr) } + map { |object| attr_value(object, attr) } end def unique_attrs(attr) to_h(attr).keys end + def group_by(attr = nil, &block) + return to_h(attr) if attr + to_a.group_by(&block) if block + end + + def to_h(attr) + return {} if !attr + to_a.group_by { |object| object.method(attr).call } + end + # @!endgroup + + # @!group `attr` presence methods def present(attr, flag = true) - block = ->(o) { !!fetch_attr(o, attr) == !!flag } + block = ->(o) { attr_value_present?(o, attr) == !!flag } newFrom select(&block) end def empty(attr, flag = true) present(attr, !flag) @@ -146,50 +155,62 @@ end def present_some?(attr, flag = true) present(attr, flag).length > 0 end + # @!endgroup - def contains(attr, value, modifier = Language::MatchModifier.new) - modifier = modifier.new.pattern - self.attr(attr, value, modifier) - end - - def group_by(attr = nil, &block) - return to_h(attr) if attr - to_a.group_by(&block) if block - end - - def to_h(attr) - return {} if !attr - to_a.group_by { |object| object.method(attr).call } - end - protected def on_change # function to be overriden by children classes end def into_a(value) - value = [].push(value) unless value.is_a?(Enumerable) + value = [].push(value) if value.is_a?(Hash) || !value.is_a?(Enumerable) value.to_a end private + def attr_value(obj, attr) + return nil unless obj && attr + case + when obj.is_a?(Hash) + obj[attr] + when obj.respond_to?(attr.to_sym) + obj.send(attr) + end + end + + def attr_value_present?(obj, attr) + return false unless value = attr_value(obj, attr) + case + when value.is_a?(Enumerable) + value.count > 1 + when value.is_a?(String) + !value.strip.empty? + else + !!value + end + end + def match?(*args) @handy.match?(*args) end def to_klass(list) into_a(list).map do |v| v.is_a?(@klass) ? v : @factory&.new(v) || @klass.new(v) end end - def fetch_attr(object,attr) - object.method(attr).call + def default_modifier + Language::MatchModifier.new + end + + def boolean?(value) + value == !!value end end end end