module React class Validator def self.build(&block) self.new.build(&block) end def build(&block) instance_eval(&block) self end def initialize @rules = {children: {required: false}} end def requires(prop_name, options = {}) rule = options options[:required] = true @rules[prop_name] = options end def optional(prop_name, options = {}) rule = options options[:required] = false @rules[prop_name] = options end def all_others(prop_name) @all_others = {} end def collect_all_others(params) Hash[params.collect { |prop_name, value| [prop_name, value] if @rules[prop_name] == nil}.compact] end def type_check(errors, error_prefix, object, klass, nil_allowed) return if !object and nil_allowed is_native = !object.respond_to?(:is_a?) rescue true if is_native or !object.is_a? klass unless klass.respond_to? :_react_param_conversion and klass._react_param_conversion(object, :validate_only) errors << "#{error_prefix} could not be converted to #{klass}" end end end def validate(props) errors = [] if @all_others props.each do |prop_name, value| @all_others[prop_name] = value if @rules[prop_name] == nil end else props.keys.each do |prop_name| errors << "Provided prop `#{prop_name}` not specified in spec" if @rules[prop_name] == nil end end props = props.select {|key| @rules.keys.include?(key) } # requires or not (@rules.keys - props.keys).each do |prop_name| errors << "Required prop `#{prop_name}` was not specified" if @rules[prop_name][:required] end # type checking props.each do |prop_name, value| if klass = @rules[prop_name][:type] is_klass_array = klass.is_a?(Array) and klass.length > 0 rescue nil if is_klass_array value_is_array_like = value.respond_to?(:each_with_index) rescue nil if value_is_array_like value.each_with_index { |ele, i| type_check(errors, "Provided prop `#{prop_name}`[#{i}]", ele, klass[0], @rules[prop_name][:allow_nil]) } else errors << "Provided prop `#{prop_name}` was not an Array" end else type_check(errors, "Provided prop `#{prop_name}`", value, klass, @rules[prop_name][:allow_nil]) end end end # values props.each do |prop_name, value| if values = @rules[prop_name][:values] errors << "Value `#{value}` for prop `#{prop_name}` is not an allowed value" unless values.include?(value) end end errors end def default_props @rules .select {|key, value| value.keys.include?("default") } .inject({}) {|memo, (k,v)| memo[k] = v[:default]; memo} end end end