lib/set_builder/modifier/base.rb in set_builder-2.0.0.beta2 vs lib/set_builder/modifier/base.rb in set_builder-2.0.0.beta3

- old
+ new

@@ -1,109 +1,116 @@ module SetBuilder module Modifier class Base - - - - def initialize(hash) - @operator, @values = (hash.is_a?(Hash) ? [hash.first[0].to_sym, hash.first[1]] : [nil, nil]) - @values ||= [] - @values = [@values] unless @values.is_a?(Array) - end - - - attr_reader :operator, :values - + + + + def initialize(params) + params.symbolize_keys! + @operator = params[:operator] + @operator = @operator.to_sym if @operator + @values = Array(params[:values]) + end + + + def value values[0] end - - - + + + def valid? - valid_operator?(self.operator) && valid_arguments?(self.values) + errors.none? end - - - - def valid_operator?(operator) - !operator.nil? && self.class.operators.key?(operator) + + def errors + [].tap do |errors| + errors.concat errors_with_operator + errors.concat errors_with_values + end end - - - - def valid_arguments?(values) - argument_types = self.class.operators[operator] || [] - return false unless (values.length == argument_types.length) - values.each_with_index do |value, i| - return false unless valid_argument_of_type?(value, argument_types[i]) + + def errors_with_operator + [].tap do |errors| + if operator.blank? + errors.push "operator is blank" + else + errors.push "#{operator.inspect} is not recognized. It should be #{self.class.operators.keys.map(&:inspect).to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" unless self.class.operators.key?(operator) + end end - true end - - - - def valid_argument_of_type?(argument, type) - validator = "valid_#{type}_argument?" + + def errors_with_values + [].tap do |errors| + types = self.class.operators[operator] || [] + if values.length != types.length + errors.push "wrong number of arguments; expected #{types.length} (#{types.join(", ")})" + else + errors.concat values.each_with_index.flat_map { |value, i| errors_with_value_type(value, types[i]) } + end + end + end + + def errors_with_value_type(value, type) + validator = "errors_with_#{type}_value" if respond_to?(validator) - send(validator, argument) + Array(public_send(validator, value)).compact else - true + [] end end - - - - def valid_date_argument?(string) - begin - Date.parse(string) - true - rescue - false - end - end - def valid_number_argument?(number) - !(number.to_s =~ /\A\d+\Z/).nil? + + def errors_with_date_value(string) + return "date is blank" if string.to_s.blank? + Date.parse(string.to_s) + nil + rescue + "#{string.inspect} is not a valid date" end - - - + + def errors_with_number_value(string) + return "number is blank" if string.to_s.blank? + "#{string.inspect} is not a valid number" unless string.to_s =~ /\A\d+\Z/ + end + + + def to_s(negative=false) words = negative ? [self.class.negate(operator).to_s.gsub(/_/, " ")] : [operator.to_s.gsub(/_/, " ")] arguments = self.class.operators[operator] || [] (0...arguments.length).each do |i| - # p "ValueMap.to_s(#{arguments[i]} (#{arguments[i].class}), #{values[i]} (#{values[i].class})): #{ValueMap.to_s(arguments[i], values[i])}" words << ValueMap.to_s(arguments[i], values[i]) end words.join(" ") end - - - + + + def self.negate(operator) operator end - - - + + + def self.to_hash hash = {} operators.each do |operator, array| hash[operator.to_s] = array.map {|type| type.to_s } end hash end - - - + + + def self.to_json to_hash.to_json end - - - + + + end end -end \ No newline at end of file +end