module JCR

Copyright © 2017 American Registry for Internet Numbers

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Copyright © 2017 American Registry for Internet Numbers

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Copyright © 2016-2017 American Registry for Internet Numbers

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Constants

VERSION

Public Class Methods

annotations_to_s( annotations ) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 524
def self.annotations_to_s( annotations )
  retval = ""
  annotations.each do |a|
    case
      when a[:unordered_annotation]
        retval = retval + "@{unordered}"
      when a[:not_annotation]
        retval = retval + "@{not}"
      when a[:root_annotation]
        retval = retval + "@{root}"
      else
        retval = retval + "@{ ** unknown annotation ** }"
    end
  end if annotations
  retval = retval + " " if retval.length != 0
  return retval
end
array_to_s( jcr, shallow=true ) click to toggle source
# File lib/jcr/evaluate_array_rules.rb, line 305
def self.array_to_s( jcr, shallow=true )
  rules, annotations = get_rules_and_annotations( jcr )
  return "#{annotations_to_s( annotations)}[ #{rules_to_s( rules, shallow )} ]"
end
bad_value(jcr, rule_atom, expected, actual) click to toggle source
# File lib/jcr/evaluate_value_rules.rb, line 404
def self.bad_value jcr, rule_atom, expected, actual
  Evaluation.new( false, "expected << #{expected} >> but got << #{actual} >> for #{raised_rule(jcr,rule_atom)}" )
end
breakup_message( message, line_length ) click to toggle source
# File lib/jcr/jcr.rb, line 177
def self.breakup_message( message, line_length )
  line = message.gsub(/(.{1,#{line_length}})(\s+|\Z)/, "\\1\n")
  lines = []
  line.each_line do |l|
    lines << l.strip
  end
  return lines
end
check_array_for_group(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 107
def self.check_array_for_group node, mapping
  if node.is_a?( Array )
    node.each do |child_node|
      check_array_for_group( child_node, mapping )
    end
  elsif node.is_a? Hash
    if node[:target_rule_name]
      trule = get_name_mapping(node[:target_rule_name][:rule_name], mapping)
      disallowed_group_in_array?(trule, mapping)
    elsif node[:group_rule]
      disallowed_group_in_array?(node[:group_rule], mapping)
    end
  end
end
check_groups( tree, mapping ) click to toggle source
# File lib/jcr/check_groups.rb, line 21
def self.check_groups( tree, mapping )
  if tree.is_a? Array
    tree.each do |node|
      check_groups( node, mapping )
    end
  else # is a hash
    if tree[:rule]
      check_groups( tree[:rule], mapping )
    elsif tree[:primitive_rule]
      check_value_for_group( tree[:primitive_rule], mapping )
    elsif tree[:member_rule]
      check_member_for_group( tree[:member_rule], mapping )
    elsif tree[:array_rule]
      check_array_for_group( tree[:array_rule], mapping )
    elsif tree[:object_rule]
      check_object_for_group( tree[:object_rule], mapping )
    end
  end
end
check_member_for_group(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 72
def self.check_member_for_group node, mapping
  if node.is_a? Array
    node = node[0]
  end
  if node[:target_rule_name]
    trule = get_name_mapping( node[:target_rule_name][:rule_name], mapping )
    disallowed_group_in_member?( trule, mapping )
  elsif node[:group_rule]
    disallowed_group_in_member?( node[:group_rule], mapping )
  end
end
check_object_for_group(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 140
def self.check_object_for_group node, mapping
  if node.is_a?( Array )
    node.each do |child_node|
      check_object_for_group( child_node, mapping )
    end
  elsif node.is_a? Hash
    if node[:target_rule_name]
      trule = get_name_mapping(node[:target_rule_name][:rule_name], mapping)
      disallowed_group_in_object?(trule, mapping)
    elsif node[:group_rule]
      disallowed_group_in_object?(node[:group_rule], mapping)
    end
  end
end
check_rule_target_names( node, mapping ) click to toggle source
# File lib/jcr/map_rule_names.rb, line 45
def self.check_rule_target_names( node, mapping )
  if node.is_a? Array
    node.each do |child_node|
      check_rule_target_names( child_node, mapping )
    end
  elsif node.is_a? Hash
    if node[:target_rule_name] && !mapping[ node[:target_rule_name][:rule_name].to_str ]
      raise_rule_name_missing node[:target_rule_name][:rule_name]
    else
      if node[:rule]
        check_rule_target_names( node[:rule], mapping )
      elsif node[:group_rule]
        check_rule_target_names( node[:group_rule], mapping )
      elsif node[:primitive_rule]
        check_rule_target_names( node[:primitive_rule], mapping )
      elsif node[:array_rule]
        check_rule_target_names( node[:array_rule], mapping )
      elsif node[:object_rule]
        check_rule_target_names( node[:object_rule], mapping )
      elsif node[:member_rule]
        check_rule_target_names( node[:member_rule], mapping )
      end
    end
  end
end
check_value_for_group(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 41
def self.check_value_for_group node, mapping
  if node.is_a?( Hash ) && node[:group_rule]
    disallowed_group_in_value?( node[:group_rule], mapping )
  end
end
cli_eval(ctx, data, root_name, quiet) click to toggle source
# File lib/jcr/jcr.rb, line 385
def self.cli_eval ctx, data, root_name, quiet
  ec = 2
  e = ctx.evaluate( data, root_name )
  if e.success
    unless quiet
      puts "Success!"
    end
    ec = 0
  else
    unless quiet
      puts "Failure! Use -v for more information."
      ctx.failure_report.each do |line|
        puts line
      end
    end
    ec = 3
  end
  return ec
end
disallowed_group_in_array?(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 122
def self.disallowed_group_in_array? node, mapping
  if node.is_a? Hash
    node = [ node ]
  end
  node.each do |groupee|
    if groupee[:group_rule]
      disallowed_group_in_array?( groupee[:group_rule], mapping )
    elsif groupee[:target_rule_name]
      trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
      disallowed_group_in_array?( trule, mapping )
    elsif groupee[:member_rule]
      raise_group_error( "groups in array rules cannot have member rules", groupee[:member_rule] )
    else
      check_groups( groupee, mapping )
    end
  end
end
disallowed_group_in_member?(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 84
def self.disallowed_group_in_member? node, mapping
  if node.is_a? Hash
    node = [ node ]
  end
  node.each do |groupee|
    if groupee[:sequence_combiner]
      raise_group_error( 'AND (comma) operation in group rule of member rule', groupee[:sequence_combiner] )
    end
    if groupee[:group_rule]
      disallowed_group_in_member?( groupee[:group_rule], mapping )
    elsif groupee[:target_rule_name]
      trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
      if trule[:group_rule]
        disallowed_group_in_member?( trule[:group_rule], mapping )
      end
    elsif groupee[:member_rule]
      raise_group_error( "groups in member rules cannot have member rules", groupee[:member_rule] )
    else
      check_groups( groupee, mapping )
    end
  end
end
disallowed_group_in_object?(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 155
def self.disallowed_group_in_object? node, mapping
  if node.is_a? Hash
    node = [ node ]
  end
  node.each do |groupee|
    if groupee[:group_rule]
      disallowed_group_in_object?( groupee[:group_rule], mapping )
    elsif groupee[:target_rule_name]
      trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
      disallowed_group_in_object?( trule, mapping )
    elsif groupee[:array_rule]
      raise_group_error( "groups in object rules cannot have array rules", groupee[:member_rule] )
    elsif groupee[:object_rule]
      raise_group_error( "groups in object rules cannot have other object rules", groupee[:member_rule] )
    elsif groupee[:primitive_rule]
      raise_group_error( "groups in object rules cannot have value rules", groupee[:member_rule] )
    else
      check_groups( groupee, mapping )
    end
  end
end
disallowed_group_in_value?(node, mapping) click to toggle source
# File lib/jcr/check_groups.rb, line 47
def self.disallowed_group_in_value? node, mapping
  if node.is_a? Hash
    node = [ node ]
  end
  node.each do |groupee|
    if groupee[:sequence_combiner]
      raise_group_error( 'AND (comma) operation in group rule of value rule', groupee[:sequence_combiner] )
    end
    if groupee[:group_rule]
      disallowed_group_in_value?( groupee[:group_rule], mapping )
    elsif groupee[:target_rule_name]
      trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
      disallowed_group_in_value?( trule[:rule], mapping )
    elsif groupee[:member_rule]
      raise_group_error( "groups in value rules cannot have member rules", groupee[:member_rule] )
    elsif groupee[:object_rule]
      raise_group_error( "groups in value rules cannot have object rules", groupee[:member_rule] )
    elsif groupee[:array_rule]
      raise_group_error( "groups in value rules cannot have array rules", groupee[:member_rule] )
    elsif groupee[:primitive_rule]
      disallowed_group_in_value?( groupee[:primitive_rule], mapping )
    end
  end
end
elide(s) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 317
def self.elide s
  if s.length > 45
    s = s[0..41]
    s = s + " ..."
  end
  return s
end
evaluate_array(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_array_rules.rb, line 69
def self.evaluate_array jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  rules, annotations = get_rules_and_annotations( jcr )

  ordered = true

  if behavior && behavior.is_a?( ArrayBehavior )
    ordered = behavior.ordered
  end

  annotations.each do |a|
    if a[:unordered_annotation]
      ordered = false
      break
    end
  end

  # if the data is not an array
  return evaluate_not( annotations,
    Evaluation.new( false, "#{data} is not an array #{raised_rule(jcr,rule_atom)}"),
                       econs, target_annotations ) unless data.is_a? Array

  # if the array is zero length and there are zero sub-rules (it is suppose to be empty)
  return evaluate_not( annotations,
    Evaluation.new( true, nil ), econs, target_annotations ) if rules.empty? && data.empty?

  # if the array is not empty and there are zero sub-rules (it is suppose to be empty)
  return evaluate_not( annotations,
    Evaluation.new( false, "Non-empty array for #{raised_rule(jcr,rule_atom)}" ),
                       econs, target_annotations ) if rules.empty? && data.length != 0

  if ordered
    return evaluate_not( annotations, evaluate_array_rule_ordered( rules, rule_atom, data, econs, behavior ),
                         econs, target_annotations )
  else
    return evaluate_not( annotations, evaluate_array_rule_unordered( rules, rule_atom, data, econs, behavior ),
                         econs, target_annotations )
  end
end
evaluate_array_rule(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_array_rules.rb, line 48
def self.evaluate_array_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  push_trace_stack( econs, jcr )
  if behavior
    trace( econs, "Evaluating group in array rule starting at #{slice_to_s(jcr)} against", data )
    trace_def( econs, "array group", jcr, data )
  else
    trace( econs, "Evaluating array rule starting at #{slice_to_s(jcr)} against", data )
    trace_def( econs, "array", jcr, data )
  end
  retval = evaluate_array( jcr, rule_atom, data, econs, behavior, target_annotations )
  if behavior
    trace_eval( econs, "Array group", retval, jcr, data, "array" )
  else
    trace_eval( econs, "Array", retval, jcr, data, "array" )
  end
  pop_trace_stack( econs )
  return retval

end
evaluate_array_rule_ordered(jcr, rule_atom, data, econs, behavior = nil) click to toggle source
# File lib/jcr/evaluate_array_rules.rb, line 109
def self.evaluate_array_rule_ordered jcr, rule_atom, data, econs, behavior = nil
  retval = nil

  behavior = ArrayBehavior.new unless behavior
  array_index = behavior.last_index


  jcr.each do |rule|

    # short circuit logic
    if rule[:choice_combiner] && retval && retval.success
      next
    elsif rule[:sequence_combiner] && retval && !retval.success
      break
    end

    repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )

    # group rules must be evaluated differently
    # groups require the effects of the evaluation to be discarded if they are false
    # groups must also be given the entire array

    grule, target_annotations = get_group( rule, econs )
    if grule

      if repeat_min == 0
        retval = Evaluation.new( true, nil )
      else
        for i in 1..repeat_min do
          if array_index == data.length
            return Evaluation.new( false, "array is not large enough for #{raised_rule(jcr,rule_atom)}" )
          else
            group_behavior = ArrayBehavior.new( behavior )
            group_behavior.last_index = array_index
            retval = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
            if retval.success
              behavior.checked_hash.merge!( group_behavior.checked_hash )
              array_index = group_behavior.last_index
            else
              break;
            end
          end
        end
      end
      if !retval || retval.success
        for i in behavior.checked_hash.length..repeat_max-1 do
          break if array_index == data.length
          group_behavior = ArrayBehavior.new( behavior )
          group_behavior.last_index = array_index
          e = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
          if e.success
            behavior.checked_hash.merge!( group_behavior.checked_hash )
            array_index = group_behavior.last_index
          else
            break;
          end
        end
      end

    else # else not grule (group)

      if repeat_min == 0
        retval = Evaluation.new( true, nil )
      else
        for i in 1..repeat_min do
          if array_index == data.length
            return Evaluation.new( false, "array is not large enough for #{raised_rule(jcr,rule_atom)}" )
          else
            retval = evaluate_rule( rule, rule_atom, data[ array_index ], econs, nil )
            break unless retval.success
            array_index = array_index + 1
            behavior.checked_hash[ i + behavior.last_index ] = retval.success
          end
        end
      end
      if !retval || retval.success
        for i in behavior.checked_hash.length..repeat_max-1 do
          break if array_index == data.length
          e = evaluate_rule( rule, rule_atom, data[ array_index ], econs, nil )
          break unless e.success
          array_index = array_index + 1
        end
      end

    end # end if grule else

    if repeat_step && ( array_index - repeat_min ) % repeat_step != 0
      retval = Evaluation.new( false, "Matches (#{array_index }) do not meat repetition step for #{repeat_max} % #{repeat_step}")
    end

  end

  behavior.last_index = array_index

  if data.length > array_index && behavior.extra_prohibited
    retval = Evaluation.new( false, "More items in array (#{data.length}) than specified (#{array_index}) for #{raised_rule(jcr,rule_atom)}" )
  end

  return retval

end
evaluate_array_rule_unordered(jcr, rule_atom, data, econs, behavior = nil) click to toggle source
# File lib/jcr/evaluate_array_rules.rb, line 211
def self.evaluate_array_rule_unordered jcr, rule_atom, data, econs, behavior = nil

  retval = nil
  unless behavior
    behavior = ArrayBehavior.new
    behavior.ordered = false
  end
  highest_index = 0

  jcr.each do |rule|

    # short circuit logic
    if rule[:choice_combiner] && retval && retval.success
      next
    elsif rule[:sequence_combiner] && retval && !retval.success
      break
    end

    repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )

    # group rules must be evaluated differently
    # groups require the effects of the evaluation to be discarded if they are false
    # groups must also be given the entire array

    grule,target_annotations = get_group(rule, econs)
    if grule

      successes = 0
      for i in 0..repeat_max-1
        group_behavior = ArrayBehavior.new( behavior )
        group_behavior.last_index = highest_index
        group_behavior.ordered = false
        e = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
        if e.success
          highest_index = group_behavior.last_index
          behavior.checked_hash.merge!( group_behavior.checked_hash )
          successes = successes + 1
        else
          break;
        end
      end

      if successes == 0 && repeat_min > 0
        retval = Evaluation.new( false, "array does not contain #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif successes < repeat_min
        retval = Evaluation.new( false, "array does not have enough #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif successes > repeat_max
        retval = Evaluation.new( false, "array has too many #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_step && ( successes - repeat_min ) % repeat_step != 0
        retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      else
        retval = Evaluation.new( true, nil )
      end

    else # else not group rule

      successes = 0
      for i in behavior.last_index..data.length-1
        break if successes == repeat_max
        unless behavior.checked_hash[ i ]
          e = evaluate_rule( rule, rule_atom, data[ i ], econs, nil )
          if e.success
            behavior.checked_hash[ i ] = e.success
            highest_index = i if i > highest_index
            successes = successes + 1
          end
        end
      end

      if successes == 0 && repeat_min > 0
        retval = Evaluation.new( false, "array does not contain #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif successes < repeat_min
        retval = Evaluation.new( false, "array does not have enough #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif successes > repeat_max
        retval = Evaluation.new( false, "array has too many #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_step && ( successes - repeat_min ) % repeat_step != 0
        retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      else
        retval = Evaluation.new( true, nil)
      end

    end # if grule else

  end

  behavior.last_index = highest_index

  if data.length > behavior.checked_hash.length && behavior.extra_prohibited
    retval = Evaluation.new( false, "More items in array #{data.length} than specified #{behavior.checked_hash.length} for #{raised_rule(jcr,rule_atom)}" )
  end

  return retval
end
evaluate_callback(jcr, data, econs, callback, e) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 146
def self.evaluate_callback jcr, data, econs, callback, e
  retval = e
  c = econs.callbacks[ callback ]
  if e.success
    retval = c.jcr_callback :rule_eval_true, jcr, data
  else
    retval = c.jcr_callback :rule_eval_false, jcr, data, e
  end
  if retval.is_a? TrueClass
    retval = Evaluation.new( true, nil )
  elsif retval.is_a? FalseClass
    retval = Evaluation.new( false, nil )
  elsif retval.is_a? String
    retval = Evaluation.new( false, retval )
  end
  trace( econs, "Callback #{callback} given evaluation of #{e.success} and returned #{retval}")
  return retval
end
evaluate_group(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_group_rules.rb, line 41
def self.evaluate_group jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  rules, annotations = get_rules_and_annotations( jcr )

  retval = nil

  rules.each do |rule|
    if rule[:choice_combiner] && retval && retval.success
      return evaluate_not( annotations, retval, econs, target_annotations ) # short circuit
    elsif rule[:sequence_combiner] && retval && !retval.success
      return evaluate_not( annotations, retval, econs, target_annotations ) # short circuit
    end
    retval = evaluate_rule( rule, rule_atom, data, econs, behavior )
  end

  return evaluate_not( annotations, retval, econs, target_annotations )
end
evaluate_group_rule(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_group_rules.rb, line 29
def self.evaluate_group_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  push_trace_stack( econs, jcr )
  trace( econs, "Evaluating group rule against ", data )
  trace_def( econs, "group", jcr, data )
  retval = evaluate_group( jcr, rule_atom, data, econs, behavior, target_annotations )
  trace_eval( econs, "Group", retval, jcr, data, "group" )
  pop_trace_stack( econs )
  return retval

end
evaluate_member(jcr, rule_atom, data, econs, behavior, target_annotations) click to toggle source
# File lib/jcr/evaluate_member_rules.rb, line 40
def self.evaluate_member jcr, rule_atom, data, econs, behavior, target_annotations

  # unlike the other evaluate functions, here data is not just the json data.
  # it is an array, the first element being the member name or regex and the
  # second being the json data to be furthered on to other evaluation functions


  rules, annotations = get_rules_and_annotations( jcr )
  rule = merge_rules( rules )

  member_match = false

  if rule[:member_name]
    match_spec = rule[:member_name][:q_string].to_s
    if match_spec == data[ 0 ]
      member_match = true
    end
  else # must be regex
    regex = rule[:member_regex][:regex]
    if regex.is_a? Array
      match_spec = Regexp.new( "" )
      trace( econs, "Noting empty regular expression." )
    else
      match_spec = Regexp.new( rule[:member_regex][:regex].to_s )
    end
    if match_spec =~ data[ 0 ]
      member_match = true
    end
  end

  if member_match
    e = evaluate_rule( rule, rule_atom, data[ 1 ], econs, nil, target_annotations )
    e.member_found = true
    return evaluate_not( annotations, e, econs, target_annotations )
  end

  return evaluate_not( annotations,
     Evaluation.new( false, "#{match_spec} does not match #{data[0]} for #{raised_rule( jcr, rule_atom)}" ),
                       econs, target_annotations )

end
evaluate_member_rule(jcr, rule_atom, data, econs, behavior, target_annotations) click to toggle source
# File lib/jcr/evaluate_member_rules.rb, line 28
def self.evaluate_member_rule jcr, rule_atom, data, econs, behavior, target_annotations

  push_trace_stack( econs, jcr )
  trace( econs, "Evaluating member rule for key '#{data[0]}' starting at #{slice_to_s(jcr)} against ", data[1])
  trace_def( econs, "member", jcr, data )
  retval = evaluate_member( jcr, rule_atom, data, econs, behavior, target_annotations )
  trace_eval( econs, "Member", retval, jcr, data, "member" )
  pop_trace_stack( econs )
  return retval

end
evaluate_not(annotations, evaluation, econs, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 264
def self.evaluate_not annotations, evaluation, econs, target_annotations = nil
  is_not = false

  target_annotations.each do |a|
    if a[:not_annotation]
      trace( econs, "Not annotation found on reference to rule.")
      is_not = !is_not
      break
    end
  end if target_annotations

  annotations.each do |a|
    if a[:not_annotation]
      is_not = !is_not
      break
    end
  end

  if is_not
    trace( econs, "Not annotation changing result from #{evaluation.success} to #{!evaluation.success}")
    evaluation.success = !evaluation.success
  end
  return evaluation
end
evaluate_object(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_object_rules.rb, line 51
def self.evaluate_object jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  rules, annotations = get_rules_and_annotations( jcr )

  # if the data is not an object (Hash)
  return evaluate_not( annotations,
    Evaluation.new( false, "#{data} is not an object for #{raised_rule(jcr,rule_atom)}"),
                    econs, target_annotations ) unless data.is_a? Hash

  # if the object has no members and there are zero sub-rules (it is suppose to be empty)
  return evaluate_not( annotations,
    Evaluation.new( true, nil ), econs, target_annotations ) if rules.empty? && data.length == 0

  # if the object has members and there are zero sub-rules (it is suppose to be empty)
  return evaluate_not( annotations,
    Evaluation.new( false, "Non-empty object for #{raised_rule(jcr,rule_atom)}" ),
                       econs, target_annotations ) if rules.empty? && data.length != 0

  retval = nil
  behavior = ObjectBehavior.new unless behavior

  rules.each do |rule|

    # short circuit logic
    if rule[:choice_combiner] && retval && retval.success
      next
    elsif rule[:sequence_combiner] && retval && !retval.success
      return evaluate_not( annotations, retval, econs, target_annotations ) # short circuit
    end

    repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )

    # Pay attention here:
    # Group rules need to be treated differently than other rules
    # Groups must be evaluated as if they are rules evaluated in
    # isolation until they evaluate as true.
    # Also, groups must be handed the entire object, not key/values
    # as member rules use.

    grule,gtarget_annotations = get_group(rule, econs)
    if grule

      successes = 0
      for i in 0..repeat_max-1
        group_behavior = ObjectBehavior.new
        group_behavior.checked_hash.merge!( behavior.checked_hash )
        e = evaluate_rule( grule, rule_atom, data, econs, group_behavior, gtarget_annotations )
        if e.success
          behavior.checked_hash.merge!( group_behavior.checked_hash )
          successes = successes + 1
        else
          break;
        end
      end

      if successes == 0 && repeat_min > 0
        retval = Evaluation.new( false, "object does not contain group #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif successes < repeat_min
        retval = Evaluation.new( false, "object does not have contain necessary number of group #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_step && ( successes - repeat_min ) % repeat_step != 0
        retval = Evaluation.new( false, "object matches (#{successes}) do not have contain repetition #{repeat_max} % #{repeat_step} of group #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      else
        retval = Evaluation.new( true, nil )
      end

    else # if not grule

      repeat_results = nil
      member_found = false

      # do a little lookahead for member rules defined by names
      # if defined by a name, and not a regex, just pluck it from the object
      # and short-circuit the enumeration

      lookahead, ltarget_annotations = get_leaf_rule( rule, econs )
      lrules, lannotations = get_rules_and_annotations( lookahead[:member_rule] )
      if lrules[0][:member_name]

        repeat_results = {}
        k = lrules[0][:member_name][:q_string].to_s
        v = data[k]
        if v
          unless behavior.checked_hash[k]
            e = evaluate_rule(rule, rule_atom, [k, v], econs, nil, nil)
            behavior.checked_hash[k] = e.success
            member_found = true if e.member_found
            repeat_results[ k ] = v if e.success
          end
        else
          trace( econs, "No member '#{k}' found in object.")
          e = evaluate_rule(rule, rule_atom, [nil, nil], econs, nil, nil)
          repeat_results[ nil ] = nil if e.success
        end

      else

        regex = lrules[0][:member_regex][:regex]
        trace( econs, "Scanning object for #{regex}.")
        i = 0
        found = false
        repeat_results = data.select do |k,v|
          unless behavior.checked_hash[k]
            if i < repeat_max
              e = evaluate_rule(rule, rule_atom, [k, v], econs, nil, nil)
              behavior.checked_hash[k] = e.success
              i = i + 1 if e.success
              found = true if e.member_found
              member_found = true if e.member_found
              e.success
            end
          end
        end
        unless found
          trace( econs, "No member matching #{regex} found in object.")
          e = evaluate_rule(rule, rule_atom, [nil, nil], econs, nil, nil)
          repeat_results[ nil ] = nil if e.success
        end

      end

      trace( econs, "Found #{repeat_results.length} matching members repetitions in object with min #{repeat_min} and max #{repeat_max}" )
      if repeat_results.length == 0 && repeat_min > 0
        retval = Evaluation.new( false, "object does not contain #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_results.length < repeat_min
        retval = Evaluation.new( false, "object does not have enough #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_results.length > repeat_max
        retval = Evaluation.new( false, "object has too many #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif repeat_step && ( repeat_results.length - repeat_min ) % repeat_step != 0
        retval = Evaluation.new( false, "object matches (#{repeat_results.length}) does not match repetition step of #{repeat_max} & #{repeat_step} for #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
      elsif member_found && repeat_results.length == 0 && repeat_max > 0
        retval = Evaluation.new( false, "object contains #{jcr_to_s(rule)} with member name though incorrect value for #{raised_rule(jcr,rule_atom)}")
      else
        retval = Evaluation.new( true, nil)
      end
    end

  end # end if grule else

  return evaluate_not( annotations, retval, econs, target_annotations )
end
evaluate_object_rule(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_object_rules.rb, line 30
def self.evaluate_object_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil

  push_trace_stack( econs, jcr )
  if behavior
    trace( econs, "Evaluating group in object rule starting at #{slice_to_s(jcr)} against", data )
    trace_def( econs, "object group", jcr, data )
  else
    trace( econs, "Evaluating object rule starting at #{slice_to_s(jcr)} against", data )
    trace_def( econs, "object", jcr, data )
  end
  retval = evaluate_object( jcr, rule_atom, data, econs, behavior, target_annotations )
  if behavior
    trace_eval( econs, "Object group", retval, jcr, data, "object" )
  else
    trace_eval( econs, "Object", retval, jcr, data, "object" )
  end
  pop_trace_stack( econs )
  return retval

end
evaluate_rule(jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 104
def self.evaluate_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil
  trace( econs, "Dispatching rule for #{jcr_to_s(jcr)} with data: #{data}")
  if jcr.is_a?( Hash )
    if jcr[:rule_name]
      rn = slice_to_s( jcr[:rule_name] )
      trace( econs, "Named Rule: #{rn}" )
    end
  end

  retval = Evaluation.new( false, "failed to evaluate rule properly" )
  case
    when behavior.is_a?( ArrayBehavior )
      retval = evaluate_array_rule( jcr, rule_atom, data, econs, behavior, target_annotations )
    when behavior.is_a?( ObjectBehavior )
      retval = evaluate_object_rule( jcr, rule_atom, data, econs, behavior, target_annotations )
    when jcr[:rule]
      retval = evaluate_rule( jcr[:rule], rule_atom, data, econs, behavior, target_annotations)
    when jcr[:target_rule_name]
      target, target_annotations = get_target_rule( jcr, econs )
      retval = evaluate_rule( target, target, data, econs, behavior, target_annotations )
    when jcr[:primitive_rule]
      retval = evaluate_value_rule( jcr[:primitive_rule], rule_atom, data, econs, nil, target_annotations )
    when jcr[:group_rule]
      retval = evaluate_group_rule( jcr[:group_rule], rule_atom, data, econs, behavior, target_annotations)
    when jcr[:array_rule]
      retval = evaluate_array_rule( jcr[:array_rule], rule_atom, data, econs, behavior, target_annotations )
    when jcr[:object_rule]
      retval = evaluate_object_rule( jcr[:object_rule], rule_atom, data, econs, behavior, target_annotations)
    when jcr[:member_rule]
      retval = evaluate_member_rule( jcr[:member_rule], rule_atom, data, econs, nil, target_annotations)
    else
      retval = Evaluation.new( true, nil )
  end
  if jcr.is_a?( Hash ) && jcr[:rule_name]
    rn = jcr[:rule_name].to_s
    if econs.callbacks[ rn ]
      retval = evaluate_callback( jcr, data, econs, rn, retval )
    end
  end
  return retval
end
evaluate_ruleset( data, ctx, root_name = nil ) click to toggle source
# File lib/jcr/jcr.rb, line 119
def self.evaluate_ruleset( data, ctx, root_name = nil )
  roots = []
  if root_name
    root_rule = ctx.mapping[root_name]
    raise JcrValidatorError, "No rule by the name of #{root_name} for a root rule has been found" unless root_rule
    root = JCR::Root.new( root_rule, root_name )
    roots << root
  else
    roots = ctx.roots
  end

  raise JcrValidatorError, "No root rule defined. Specify a root rule name" if roots.empty?

  retval = nil
  roots.each do |r|
    pp "Evaluating Root:", rule_to_s( r.rule, false ) if ctx.trace
    raise JcrValidatorError, "Root rules cannot be member rules" if r.rule[:member_rule]
    econs = EvalConditions.new( ctx.mapping, ctx.callbacks, ctx.trace )
    retval = JCR.evaluate_rule( r.rule, r.rule, data, econs )
    break if retval.success
    # else
    r.failures = econs.failures
    ctx.failed_roots << r
  end

  ctx.failure_report = failure_report( ctx )
  return retval
end
evaluate_value_rule(jcr, rule_atom, data, econs, behavior, target_annotations) click to toggle source
# File lib/jcr/evaluate_value_rules.rb, line 28
def self.evaluate_value_rule jcr, rule_atom, data, econs, behavior, target_annotations

  push_trace_stack( econs, jcr )
  trace( econs, "Evaluating value rule starting at #{slice_to_s(jcr)}" )
  trace_def( econs, "value", jcr, data )
  rules, annotations = get_rules_and_annotations( jcr )

  retval = evaluate_not( annotations, evaluate_values( rules[0], rule_atom, data, econs ),
                         econs, target_annotations )
  trace_eval( econs, "Value", retval, jcr, data, "value")
  pop_trace_stack( econs )
  return retval
end
evaluate_values(jcr, rule_atom, data, econs) click to toggle source
# File lib/jcr/evaluate_value_rules.rb, line 42
def self.evaluate_values jcr, rule_atom, data, econs
  case

    #
    # any
    #

    when jcr[:any]
      return Evaluation.new( true, nil )

    #
    # integers
    #

    when jcr[:integer_v]
      si = jcr[:integer_v].to_s
      if si == "integer"
        return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
      end
    when jcr[:integer]
      i = jcr[:integer].to_s.to_i
      return bad_value( jcr, rule_atom, i, data ) unless data == i
    when jcr[:integer_min] != nil && jcr[:integer_max] == nil
      return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
      min = jcr[:integer_min].to_s.to_i
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
    when jcr[:integer_min] == nil && jcr[:integer_max] != nil
      return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
      max = jcr[:integer_max].to_s.to_i
      return bad_value( jcr, rule_atom, max, data ) unless data <= max
    when jcr[:integer_min],jcr[:integer_max]
      return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
      min = jcr[:integer_min].to_s.to_i
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
      max = jcr[:integer_max].to_s.to_i
      return bad_value( jcr, rule_atom, max, data ) unless data <= max
    when jcr[:sized_int_v]
      bits = jcr[:sized_int_v][:bits].to_i
      return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?( Integer )
      min = -(2**(bits-1))
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
      max = 2**(bits-1)-1
      return bad_value( jcr, rule_atom, max, data ) unless data <= max
    when jcr[:sized_uint_v]
      bits = jcr[:sized_uint_v][:bits].to_i
      return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?( Integer )
      min = 0
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
      max = 2**bits-1
      return bad_value( jcr, rule_atom, max, data ) unless data <= max

    #
    # floats
    #

    when jcr[:float_v]
      sf = jcr[:float_v].to_s
      if sf == "float"
        return bad_value( jcr, rule_atom, "float", data ) unless data.is_a?( Float )
      end
    when jcr[:float]
      f = jcr[:float].to_s.to_f
      return bad_value( jcr, rule_atom, f, data ) unless data == f
    when jcr[:float_min] != nil && jcr[:float_max] == nil
      return bad_value( jcr, rule_atom, "float", data ) unless data.is_a?( Float )
      min = jcr[:float_min].to_s.to_f
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
    when jcr[:float_min] == nil && jcr[:float_max] != nil
      return bad_value( jcr, rule_atom, "float", data ) unless data.is_a?( Float )
      max = jcr[:float_max].to_s.to_f
      return bad_value( jcr, rule_atom, max, data ) unless data <= max
    when jcr[:float_min],jcr[:float_max]
      return bad_value( jcr, rule_atom, "float", data ) unless data.is_a?( Float )
      min = jcr[:float_min].to_s.to_f
      return bad_value( jcr, rule_atom, min, data ) unless data >= min
      max = jcr[:float_max].to_s.to_f
      return bad_value( jcr, rule_atom, max, data ) unless data <= max
    when jcr[:double_v]
      sf = jcr[:double_v].to_s
      if sf == "double"
        return bad_value( jcr, rule_atom, "double", data ) unless data.is_a?( Float )
      end

    #
    # boolean
    #

    when jcr[:true_v]
      return bad_value( jcr, rule_atom, "true", data ) unless data
    when jcr[:false_v]
      return bad_value( jcr, rule_atom, "false", data ) if data
    when jcr[:boolean_v]
      return bad_value( jcr, rule_atom, "boolean", data ) unless ( data.is_a?( TrueClass ) || data.is_a?( FalseClass ) )

    #
    # strings
    #

    when jcr[:string]
      return bad_value( jcr, rule_atom, "string", data ) unless data.is_a? String
    when jcr[:q_string]
      s = jcr[:q_string].to_s
      return bad_value( jcr, rule_atom, s, data ) unless data == s

    #
    # regex
    #

    when jcr[:regex]
      regex = Regexp.new( jcr[:regex].to_s )
      return bad_value( jcr, rule_atom, regex, data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, regex, data ) unless data =~ regex

    #
    # ip addresses
    #

    when jcr[:ipv4]
      return bad_value( jcr, rule_atom, "IPv4 Address", data ) unless data.is_a? String
      begin
        ip = IPAddr.new( data )
      rescue IPAddr::InvalidAddressError
        return bad_value( jcr, rule_atom, "IPv4 Address", data )
      end
      return bad_value( jcr, rule_atom, "IPv4 Address", data ) unless ip.ipv4?
    when jcr[:ipv6]
      return bad_value( jcr, rule_atom, "IPv6 Address", data ) unless data.is_a? String
      begin
        ip = IPAddr.new( data )
      rescue IPAddr::InvalidAddressError
        return bad_value( jcr, rule_atom, "IPv6 Address", data )
      end
      return bad_value( jcr, rule_atom, "IPv6 Address", data ) unless ip.ipv6?
    when jcr[:ipaddr]
      return bad_value( jcr, rule_atom, "IP Address", data ) unless data.is_a? String
      begin
        ip = IPAddr.new( data )
      rescue IPAddr::InvalidAddressError
        return bad_value( jcr, rule_atom, "IP Address", data )
      end
      return bad_value( jcr, rule_atom, "IP Address", data ) unless ip.ipv6? || ip.ipv4?

    #
    # domain names
    #

    when jcr[:fqdn]
      return bad_value( jcr, rule_atom, "Fully Qualified Domain Name", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Fully Qualified Domain Name", data ) if data.empty?
      a = data.split( '.' )
      a.each do |label|
        return bad_value( jcr, rule_atom, "Fully Qualified Domain Name", data ) if label.start_with?( '-' )
        return bad_value( jcr, rule_atom, "Fully Qualified Domain Name", data ) if label.end_with?( '-' )
        label.each_char do |char|
          unless (char >= 'a' && char <= 'z') \
            || (char >= 'A' && char <= 'Z') \
            || (char >= '0' && char <='9') \
            || char == '-'
            return bad_value( jcr, rule_atom, "Fully Qualified Domain Name", data )
          end
        end
      end
    when jcr[:idn]
      return bad_value( jcr, rule_atom, "Internationalized Domain Name", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Internationalized Domain Name", data ) if data.empty?
      a = data.split( '.' )
      a.each do |label|
        return bad_value( jcr, rule_atom, "Internationalized Domain Name", data ) if label.start_with?( '-' )
        return bad_value( jcr, rule_atom, "Internationalized Domain Name", data ) if label.end_with?( '-' )
        label.each_char do |char|
          unless (char >= 'a' && char <= 'z') \
            || (char >= 'A' && char <= 'Z') \
            || (char >= '0' && char <='9') \
            || char == '-' \
            || char.ord > 127
            return bad_value( jcr, rule_atom, "Internationalized Domain Name", data )
          end
        end
      end

    #
    # uri and uri scheme
    #

    when jcr[:uri]
      if jcr[:uri].is_a? Hash
        t = jcr[:uri][:uri_scheme].to_s
        return bad_value( jcr, rule_atom, t, data ) unless data.is_a? String
        return bad_value( jcr, rule_atom, t, data ) unless data.start_with?( t )
      else
        return bad_value( jcr, rule_atom, "URI", data ) unless data.is_a?( String )
        uri = Addressable::URI.parse( data )
        return bad_value( jcr, rule_atom, "URI", data ) unless uri.is_a?( Addressable::URI )
      end

    #
    # phone and email value rules
    #

    when jcr[:email]
      return bad_value( jcr, rule_atom, "Email Address", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Email Address", data ) unless EmailAddressValidator.validate( data, true )

    when jcr[:phone]
      return bad_value( jcr, rule_atom, "Phone Number", data ) unless data.is_a? String
      p = BigPhoney::PhoneNumber.new( data )
      return bad_value( jcr, rule_atom, "Phone Number", data ) unless p.valid?

    #
    # hex values
    #

    when jcr[:hex]
      return bad_value( jcr, rule_atom, "Hex Data", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Hex Data", data ) unless data.length % 2 == 0
      pad_start = false
      data.each_char do |char|
        unless (char >= '0' && char <='9') \
            || (char >= 'A' && char <= 'F') \
            || (char >= 'a' && char <= 'f')
          return bad_value( jcr, rule_atom, "Hex Data", data )
        end
      end

    #
    # base32hex values
    #

    when jcr[:base32hex]
      return bad_value( jcr, rule_atom, "Base32hex Data", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Base32hex Data", data ) unless data.length % 8 == 0
      pad_start = false
      data.each_char do |char|
        if char == '='
          pad_start = true
        elsif pad_start && char != '='
          return bad_value( jcr, rule_atom, "Base32hex Data", data )
        else 
            unless (char >= '0' && char <='9') \
                || (char >= 'A' && char <= 'V') \
                || (char >= 'a' && char <= 'v')
              return bad_value( jcr, rule_atom, "Base32hex Data", data )
            end
        end
      end

    #
    # base32 values
    #

    when jcr[:base32]
      return bad_value( jcr, rule_atom, "Base 32 Data", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Base 32 Data", data ) unless data.length % 8 == 0
      pad_start = false
      data.each_char do |char|
        if char == '='
          pad_start = true
        elsif pad_start && char != '='
          return bad_value( jcr, rule_atom, "Base 32 Data", data )
        else 
            unless (char >= 'a' && char <= 'z') \
                || (char >= 'A' && char <= 'Z') \
                || (char >= '2' && char <='7')
              return bad_value( jcr, rule_atom, "Base 32 Data", data )
            end
        end
      end

    #
    # base64url values
    #

    when jcr[:base64url]
      return bad_value( jcr, rule_atom, "Base64url Data", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Base64url Data", data ) unless data.length % 4 == 0
      pad_start = false
      data.each_char do |char|
        if char == '='
          pad_start = true
        elsif pad_start && char != '='
          return bad_value( jcr, rule_atom, "Base64url Data", data )
        else 
            unless (char >= 'a' && char <= 'z') \
                || (char >= 'A' && char <= 'Z') \
                || (char >= '0' && char <='9') \
                || char == '-' || char == '_'
              return bad_value( jcr, rule_atom, "Base64url Data", data )
            end
        end
      end

    #
    # base64 values
    #

    when jcr[:base64]
      return bad_value( jcr, rule_atom, "Base 64 Data", data ) unless data.is_a? String
      return bad_value( jcr, rule_atom, "Base 64 Data", data ) unless data.length % 4 == 0
      pad_start = false
      data.each_char do |char|
        if char == '='
          pad_start = true
        elsif pad_start && char != '='
          return bad_value( jcr, rule_atom, "Base 64 Data", data )
        else 
            unless (char >= 'a' && char <= 'z') \
                || (char >= 'A' && char <= 'Z') \
                || (char >= '0' && char <='9') \
                || char == '+' || char == '/'
              return bad_value( jcr, rule_atom, "Base 64 Data", data )
            end
        end
      end

    #
    # time and date values
    #

    when jcr[:datetime]
      return bad_value( jcr, rule_atom, "Time and Date", data ) unless data.is_a? String
      begin
        Time.iso8601( data )
      rescue ArgumentError
        return bad_value( jcr, rule_atom, "Time and Date", data )
      end
    when jcr[:date]
      return bad_value( jcr, rule_atom, "Date", data ) unless data.is_a? String
      begin
        d = data + "T23:20:50.52Z"
        Time.iso8601( d )
      rescue ArgumentError
        return bad_value( jcr, rule_atom, "Date", data )
      end
    when jcr[:time]
      return bad_value( jcr, rule_atom, "Time", data ) unless data.is_a? String
      begin
        t = "1985-04-12T" + data + "Z"
        Time.iso8601( t )
      rescue ArgumentError
        return bad_value( jcr, rule_atom, "Time", data )
      end

    #
    # null
    #

    when jcr[:null]
      return bad_value( jcr, rule_atom, nil, data ) unless data == nil

    #
    # groups
    #

    when jcr[:group_rule]
      return evaluate_group_rule jcr[:group_rule], rule_atom, data, econs

    else
      raise "unknown value rule evaluation. this shouldn't happen"
  end
  return Evaluation.new( true, nil )
end
failure_report(ctx) click to toggle source
# File lib/jcr/jcr.rb, line 148
def self.failure_report ctx
  report = []
  ctx.failed_roots.each do |failed_root|
    if failed_root.name
      report << "- Failures for root rule named '#{failed_root.name}'"
    else
      report << "- Failures for root rule at line #{failed_root.pos[0]}"
    end
    failed_root.failures.each_with_index do |failures,stack_level|
      if failures.length > 1
        report << "  - failure at rule level #{stack_level} caused by one of the following #{failures.length} reasons"
      else
        report << "  - failure at rule level #{stack_level} caused by"
      end
      failures.each_with_index do |failure, index|
        lines = breakup_message( "<< #{failure.json_elided} >> failed rule #{failure.definition}", ctx.failure_report_line_length - 5 )
        lines.each_with_index do |l,i|
          if i == 0
            report << "    - #{l}"
          else
            report << "      #{l}"
          end
        end
      end
    end
  end
  return report
end
find_first_slice(slice) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 413
def self.find_first_slice slice
  if slice.is_a? Parslet::Slice
    return slice
  elsif slice.is_a?( Hash ) && !slice.empty?
    s = nil
    slice.values.each do |v|
      s = find_first_slice( v )
      break if s
    end
    return s if s
  elsif slice.is_a?( Array ) && !slice.empty?
    s = nil
    slice.each do |i|
      s = find_first_slice( i )
      break if s
    end
    return s if s
  end
  #else
  return nil
end
find_roots( tree ) click to toggle source
# File lib/jcr/find_roots.rb, line 37
def self.find_roots( tree )
  roots = Array.new
  if tree.is_a? Hash
    tree = [ tree ]
  end
  tree.each do |node|
    if node[:rule]
      roots.concat( find_roots_in_named( node ) )
    elsif (top_rule = get_rule_by_type( node ))
      roots << Root.new( node, nil, true, true )
      roots.concat( find_roots_in_unnamed( top_rule ) )
    end
  end
  return roots
end
find_roots_in_named( node ) click to toggle source
# File lib/jcr/find_roots.rb, line 53
def self.find_roots_in_named( node )
  roots = Array.new
  rn = node[:rule][:rule_name].to_str
  rule = node[:rule]
  ruledef = get_rule_by_type( rule )
  new_root = nil
  # look to see if the root_annotation is in the name before assignment ( @{root} $r = ... )
  if rule[:annotations]
    if rule[:annotations].is_a? Array
      rule[:annotations].each do |annotation|
        if annotation[:root_annotation]
          new_root = Root.new(node, rn)
          roots << new_root
          # root is found, now look into subrule for unnamed roots
          subrule = get_rule_by_type( ruledef )
          roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
        end
      end
    elsif rule[:annotations][:root_annotation]
      new_root = Root.new(node, rn)
      roots << new_root
      # root is found, now look into subrule for unnamed roots
      subrule = get_rule_by_type( ruledef )
      roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
    end
  end
  if ruledef && !new_root
    if ruledef.is_a? Array
      ruledef.each do |rdi|
        # if it has a @{root} annotation in the rule definition
        if rdi[:root_annotation]
          roots << Root.new(node, rn)
          # else look into the definition further and examine subrules
        elsif (subrule = get_rule_by_type(rdi))
          roots.concat(find_roots_in_unnamed(subrule))
        end
      end
    elsif ruledef.is_a? Hash
      subrule = get_rule_by_type(ruledef)
      roots.concat(find_roots_in_unnamed(subrule)) if subrule
    end
  end
  return roots
end
find_roots_in_unnamed( node ) click to toggle source
# File lib/jcr/find_roots.rb, line 98
def self.find_roots_in_unnamed( node )
  roots = Array.new
  if node.is_a? Array
    node.each do |n|
      if n[:root_annotation]
        roots << Root.new( node )
      elsif (subrule = get_rule_by_type( n ) )
        roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
      end
    end
  else
    subrule = get_rule_by_type( node )
    roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
  end
  return roots
end
get_group(rule, econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 289
def self.get_group rule, econs
  return rule[:group_rule], nil if rule[:group_rule]
  #else
  if rule[:target_rule_name]
    target, target_annotations = get_target_rule( rule, econs )
    return get_group( target, econs )[0], target_annotations
  end
  #else
  return false, nil
end
get_leaf_rule(rule, econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 300
def self.get_leaf_rule rule, econs
  if rule[:target_rule_name ]
    target, target_annotations = get_target_rule( rule, econs )
    return target, target_annotations
  end
  #else
  return rule, nil
end
get_name_mapping(rule_name, mapping) click to toggle source
# File lib/jcr/map_rule_names.rb, line 71
def self.get_name_mapping rule_name, mapping
  trule = mapping[ rule_name.to_str ]
  raise_rule_name_missing( rule_name ) unless trule
  return trule
end
get_repetitions(rule, econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 172
def self.get_repetitions rule, econs

  repeat_min = 1
  repeat_max = 1
  repeat_step = nil
  if rule[:optional]
    repeat_min = 0
    repeat_max = 1
  elsif rule[:one_or_more]
    repeat_min = 1
    repeat_max = Float::INFINITY
    if rule[:repetition_step]
      repeat_step = rule[:repetition_step].to_s.to_i
      repeat_min = repeat_step
    end
  elsif rule[:zero_or_more]
    repeat_min = 0
    repeat_max = Float::INFINITY
    repeat_step = rule[:repetition_step].to_s.to_i if rule[:repetition_step]
  elsif rule[:specific_repetition] && rule[:specific_repetition].is_a?( Parslet::Slice )
    repeat_min = repeat_max = rule[:specific_repetition].to_s.to_i
  else
    o = rule[:repetition_interval]
    if o
      repeat_min = 0
      repeat_max = Float::INFINITY
    end
    o = rule[:repetition_min]
    if o
      if o.is_a?( Parslet::Slice )
        repeat_min = o.to_s.to_i
      end
    end
    o = rule[:repetition_max]
    if o
      if o.is_a?( Parslet::Slice )
        repeat_max = o.to_s.to_i
      end
    end
    o = rule[:repetition_step]
    if o
      if o.is_a?( Parslet::Slice )
        repeat_step = o.to_s.to_i
      end
    end
  end

  trace( econs, "rule repetition min = #{repeat_min} max = #{repeat_max} repetition step = #{repeat_step}" )
  return repeat_min, repeat_max, repeat_step
end
get_rule_by_type(rule) click to toggle source
# File lib/jcr/find_roots.rb, line 115
def self.get_rule_by_type rule
  retval = nil
  return retval unless rule.is_a? Hash
  case
    when rule[:array_rule]
      retval = rule[:array_rule]
    when rule[:object_rule]
      retval = rule[:object_rule]
    when rule[:member_rule]
      retval = rule[:member_rule]
    when rule[:primitive_rule]
      retval = rule[:primitive_rule]
    when rule[:group_rule]
      retval = rule[:group_rule]
  end
  return retval
end
get_rules_and_annotations(jcr) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 223
def self.get_rules_and_annotations jcr
  rules = []
  annotations = []

  if jcr.is_a?( Hash )
    jcr = [ jcr ]
  end

  if jcr.is_a? Array
    i = 0
    jcr.each do |sub|
      case
        when sub[:unordered_annotation]
          annotations << sub
          i = i + 1
        when sub[:not_annotation]
          annotations << sub
          i = i + 1
        when sub[:root_annotation]
          annotations << sub
          i = i + 1
        when sub[:primitive_rule],sub[:object_rule],sub[:group_rule],sub[:array_rule],sub[:target_rule_name]
          break
      end
    end
    rules = jcr[i,jcr.length]
  end

  return rules, annotations
end
get_target_rule(jcr, econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 165
def self.get_target_rule jcr, econs
  target = econs.mapping[ jcr[:target_rule_name][:rule_name].to_s ]
  raise "Target rule not in mapping. This should have been checked earlier." unless target
  trace( econs, "Referencing target rule #{slice_to_s(target)} from #{slice_to_s( jcr[:target_rule_name][:rule_name] )}" )
  return target,jcr[:target_rule_name][:annotations]
end
group_to_s( jcr, shallow=true) click to toggle source
# File lib/jcr/evaluate_group_rules.rb, line 59
def self.group_to_s( jcr, shallow=true)
  rules, annotations = get_rules_and_annotations( jcr )
  return "#{annotations_to_s( annotations)}( #{rules_to_s(rules,shallow)} )"
end
ingest_ruleset( ruleset, existing_mapping = nil, ruleset_alias=nil ) click to toggle source
# File lib/jcr/jcr.rb, line 101
def self.ingest_ruleset( ruleset, existing_mapping = nil, ruleset_alias=nil )
  tree = JCR.parse( ruleset )
  mapping = JCR.map_rule_names( tree, ruleset_alias )
  combined_mapping = {}
  combined_mapping.merge!( existing_mapping ) if existing_mapping
  combined_mapping.merge!( mapping )
  JCR.check_rule_target_names( tree, combined_mapping )
  JCR.check_groups( tree, combined_mapping )
  roots = JCR.find_roots( tree )
  ctx = Context.new
  ctx.tree = tree
  ctx.mapping = mapping
  ctx.callbacks = {}
  ctx.roots = roots
  JCR.process_directives( ctx )
  return ctx
end
jcr_to_s( jcr, shallow=true ) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 450
def self.jcr_to_s( jcr, shallow=true )
  if jcr.is_a? Array
    retval = ""
    jcr.each_with_index do |item,idx|
      if idx > 1
        retval = retval + " , "
      end
      retval = retval + jcr_to_s( item, shallow )
    end
  elsif jcr.is_a? Parslet::Slice
    retval = slice_to_s( jcr )
  else
    if jcr[:q_string]
      retval = value_to_s( jcr )
    else
      retval = rule_to_s( jcr, shallow )
    end
  end
  return "<< " + retval + " >>"
end
main(my_argv=nil) click to toggle source
# File lib/jcr/jcr.rb, line 186
def self.main my_argv=nil

  my_argv = ARGV unless my_argv

  options = {}

  opt_parser = OptionParser.new do |opt|
    opt.banner = "Usage: jcr [OPTIONS] [JSON_FILES]"
    opt.separator  ""
    opt.separator  "Evaluates JSON against JSON Content Rules (JCR)."
    opt.separator  ""
    opt.separator  "If -J is not specified, JSON_FILES is used."
    opt.separator  "If JSON_FILES is not specified, standard input (STDIN) is used."
    opt.separator  ""
    opt.separator  "Use -v to see results, otherwise check the exit code."
    opt.separator  ""
    opt.separator  "Options"

    opt.on("-r FILE","file containing ruleset") do |ruleset|
      if options[:ruleset]
        puts "A ruleset has already been specified. Use -h for help.", ""
        return 2
      end
      options[:ruleset] = File.open( ruleset ).read
    end

    opt.on("-R STRING","string containing ruleset. Should probably be quoted") do |ruleset|
      if options[:ruleset]
        puts "A ruleset has already been specified. Use -h for help.", ""
        return 2
      end
      options[:ruleset] = ruleset
    end

    opt.on("--test-jcr", "parse and test the JCR only") do |testjcr|
      options[:testjcr] = true
    end

    opt.on("--process-parts [DIRECTORY]", "creates smaller files for specification writing" ) do |directory|
      options[:process_parts] = true
      options[:process_parts_directory] = directory
    end

    opt.on("-S STRING","name of root rule. All roots will be tried if none is specified") do |root_name|
      if options[:root_name]
        puts "A root has already been specified. Use -h for help.", ""
        return 2
      end
      options[:root_name] = root_name
    end

    opt.on("-o FILE","file containing overide ruleset (option can be repeated)") do |ruleset|
      unless options[:overrides]
        options[:overrides] = Array.new
      end
      options[:overrides] << File.open( ruleset ).read
    end

    opt.on("-O STRING","string containing overide rule (option can be repeated)") do |rule|
      unless options[:overrides]
        options[:overrides] = Array.new
      end
      options[:overrides] << rule
    end

    opt.on("-J STRING","string containing JSON to evaluate. Should probably be quoted") do |json|
      if options[:json]
        puts "JSON has already been specified. Use -h for help.", ""
        return 2
      end
      options[:json] = json
    end

    opt.on("-v","verbose") do |verbose|
      options[:verbose] = true
    end

    opt.on("-q","quiet") do |quiet|
      options[:quiet] = true
    end

    opt.on("-h","display help") do |help|
      options[:help] = true
    end

    opt.separator  ""
    opt.separator  "Return codes:"
    opt.separator  " 0 = success"
    opt.separator  " 1 = bad JCR parsing or other bad condition"
    opt.separator  " 2 = invalid option or bad use of command"
    opt.separator  " 3 = unsuccessful evaluation of JSON"

    opt.separator  ""
    opt.separator  "JCR Version " + JCR::VERSION
  end

  begin
    opt_parser.parse! my_argv
  rescue OptionParser::InvalidOption => e
    puts "Unable to interpret command or options"
    puts e.message
    puts "", "Use -h for help"
    return 2
  end

  if options[:help]
    puts "HELP","----",""
    puts opt_parser
    return 2
  elsif !options[:ruleset]
    puts "No ruleset passed! Use -R or -r options.", ""
    puts "Use -h for help"
    return 2
  else

    begin

      ctx = Context.new( options[:ruleset], options[:verbose] )
      if options[:overrides]
        options[:overrides].each do |ov|
          ctx.override!( ov )
        end
      end

      if options[:verbose]
        pp "Ruleset Parse Tree", ctx.tree
        puts "Ruleset Map"
        ctx.mapping.each do |name,rule|
          puts "Parsed Rule: #{name}"
          puts rule_to_s( rule, false )
          puts "Parsed Rule Structure: #{name}"
          pp rule
        end
      end

      if options[:process_parts]
        parts = JCR::JcrParts.new
        parts.process_ruleset( options[:ruleset], options[:process_parts_directory] )
        if options[:overrides ]
          options[:overrides].each do |ov|
            parts = JCR::JcrParts.new
            parts.process_ruleset( ov, options[:process_parts_directory] )
          end
        end
      end

      if options[:testjcr]
        #we got this far which means the JCR was already parsed without
        #issue. therefore return 0
        return 0
      elsif options[:json]
        data = JSON.parse( options[:json] )
        ec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
        return ec
      elsif $stdin.tty?
        ec = 0
        if my_argv.empty?
          ec = 2
        else
          my_argv.each do |fn|
            data = JSON.parse( File.open( fn ).read )
            tec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
            ec = tec if tec != 0 #record error but don't let non-error overwrite error
          end
        end
        return ec
      else
        lines = ""
        ec = 0
        ARGF.each do |line|
          lines = lines + line
          if ARGF.eof?
            data = JSON.parse( lines )
            tec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
            ec = tec if tec != 0 #record error but don't let non-error overwrite error
            lines = ""
          end
        end
        return ec
      end

    rescue JCR::JcrValidatorError => jcr_error
      puts jcr_error.message
      return 1
    rescue Parslet::ParseFailed => failure
      puts failure.parse_failure_cause.ascii_tree unless options[:quiet]
      return 1
    rescue JSON::ParserError => parser_error
      unless options[:quiet]
        puts "Unable to parse JSON"
        puts parser_error.message.inspect
      end
      return 3
    end

  end

end
map_rule_names( tree, ruleset_alias = nil ) click to toggle source
# File lib/jcr/map_rule_names.rb, line 20
def self.map_rule_names( tree, ruleset_alias = nil )
  prefix = ""
  if ruleset_alias
    prefix = ruleset_alias
    unless prefix.end_with?( "." )
      prefix = prefix + "."
    end
  end
  rule_name_maping = Hash.new
  if tree.is_a? Hash
    tree = [ tree ]
  end
  tree.each do |node|
    if node[:rule]
      rn = prefix + node[:rule][:rule_name].to_str
      if rule_name_maping[ rn ]
        raise JCR::JcrValidatorError, "Rule #{rn} already exists and is defined more than once"
      else
        rule_name_maping[ rn ] = node[:rule]
      end
    end
  end
  return rule_name_maping
end
member_to_s( jcr, shallow=true ) click to toggle source
# File lib/jcr/evaluate_member_rules.rb, line 82
def self.member_to_s( jcr, shallow=true )
  rules, annotations = get_rules_and_annotations( jcr )
  retval = ""
  rule = merge_rules( rules )
  case
    when rule[:member_name]
      retval = %Q|"#{rule[:member_name][:q_string].to_s}"|
    when rule[:member_regex]
      retval = "/#{rule[:member_regex][:regex].to_s}/"
    else
      retval = "** unknown member rule **"
  end
  retval = retval + " : " + rule_to_s( rule, shallow )
  return annotations_to_s( annotations ) + retval
end
merge_rules(rules) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 254
def self.merge_rules rules
  new_rule = Hash.new
  rules.each do |rule|
    new_rule.merge!(rule) do |key,oldval,newval|
      raise "error: conflict in merge of #{rule} with #{new_rule}"
    end
  end
  return new_rule
end
object_to_s( jcr, shallow=true ) click to toggle source
# File lib/jcr/evaluate_object_rules.rb, line 192
def self.object_to_s( jcr, shallow=true )
  rules, annotations = get_rules_and_annotations( jcr )
  return "#{annotations_to_s( annotations)}{ #{rules_to_s(rules,shallow)} }"
end
parse(str) click to toggle source
# File lib/jcr/parser.rb, line 462
def self.parse(str)

  parser = Parser.new
  parser.parse(str)

end
parse_and_transform(str) click to toggle source
# File lib/jcr/parser.rb, line 469
def self.parse_and_transform(str)
  # provided for the fun of it

  parser = Parser.new
  tree = parser.parse(str)
  pp tree

  transformer = Transformer.new
  transformer.apply( tree )

end
pop_trace_stack(econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 313
def self.pop_trace_stack econs
  econs.trace_stack.pop
end
print_tree( tree ) click to toggle source
process_directives( ctx ) click to toggle source
# File lib/jcr/process_directives.rb, line 25
def self.process_directives( ctx )

  tree = ctx.tree
  if tree.is_a? Hash
    tree = [ tree ]
  end

  tree.each do |node|
    if node[:directive]
      d = node[:directive]
      case
        when d[:ruleset_id_d]
          process_ruleset_id( d[:ruleset_id_d], ctx )
        when d[:import_d]
          process_import( d[:import_d], ctx )
        when d[:jcr_version_d]
          process_jcrversion( d[:jcr_version_d], ctx )
      end
    end
  end
end
process_import( directive, ctx ) click to toggle source
# File lib/jcr/process_directives.rb, line 62
def self.process_import( directive, ctx )

  ruleset_id    = directive[:ruleset_id].to_str
  ruleset_alias = directive[:ruleset_id_alias].to_str
  u = ctx.map_ruleset_alias( ruleset_alias, ruleset_id )
  uri = URI.parse( u )
  ruleset = nil
  case uri.scheme
    when "http","https"
      response = Net::HTTP.get_response uri
      ruleset = response.body
    else
      ruleset = File.open( uri.path )
  end

  import_ctx = JCR.ingest_ruleset( ruleset, nil, ruleset_alias )
  ctx.mapping.merge!( import_ctx.mapping )
  ctx.roots.concat( import_ctx.roots )

end
process_jcrversion( directive, ctx ) click to toggle source
# File lib/jcr/process_directives.rb, line 51
def self.process_jcrversion( directive, ctx )
  major = directive[:major_version].to_str.to_i
  minor = directive[:minor_version].to_str.to_i
  if major != 0
    raise "jcr version #{major}.#{minor} is incompatible with 0.7"
  end
  if minor != 7
    raise "jcr version #{major}.#{minor} is incompatible with 0.7"
  end
end
process_ruleset_id( directive, ctx ) click to toggle source
# File lib/jcr/process_directives.rb, line 47
def self.process_ruleset_id( directive, ctx )
  ctx.id = directive[:ruleset_id].to_str
end
push_trace_stack(econs, jcr) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 309
def self.push_trace_stack econs, jcr
  econs.trace_stack.push( find_first_slice( jcr ) )
end
raise_group_error(str, node) click to toggle source
# File lib/jcr/check_groups.rb, line 177
def self.raise_group_error str, node
  if node.is_a?( Parslet::Slice )
    pos = node.line_and_column
    name = node.to_str
    raise JCR::JcrValidatorError, "group rule error at line " + pos[0].to_s + " column " + pos[1].to_s + " name '" + name + "' :" + str
  else
    raise JCR::JcrValidatorError, "group rule error with '" + node.to_s + "' :" + str
  end
end
raise_rule_name_missing(rule_name) click to toggle source
# File lib/jcr/map_rule_names.rb, line 77
def self.raise_rule_name_missing rule_name
  pos = rule_name.line_and_column
  name = rule_name.to_str
  raise JCR::JcrValidatorError,
        "rule '" + name + "' at line " + pos[0].to_s + " column " + pos[1].to_s + " does not exist"
end
raised_rule(jcr, rule_atom) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 446
def self.raised_rule jcr, rule_atom
  " rule at #{slice_to_s(jcr)} #{jcr_to_s(jcr)} from rule at #{slice_to_s(rule_atom)}"
end
repetitions_to_s(rule) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 546
def self.repetitions_to_s rule
  retval = ""
  if rule[:optional]
    retval = "?"
  elsif rule[:one_or_more]
    retval = "+"
    if rule[:repetition_step]
      retval = "%" + rule[:repetition_step].to_s
    end
  elsif rule[:zero_or_more]
    retval = "*"
    retval = retval + "%" + rule[:repetition_step].to_s if rule[:repetition_step]
  elsif rule[:specific_repetition] && rule[:specific_repetition].is_a?( Parslet::Slice )
    retval = "*" + rule[:specific_repetition].to_s
  else
    if rule[:repetition_interval]
      min = "0"
      max = "INF"
      o = rule[:repetition_min]
      if o
        if o.is_a?(Parslet::Slice)
          min = o.to_s
        end
      end
      o = rule[:repetition_max]
      if o
        if o.is_a?(Parslet::Slice)
          max = o.to_s
        end
      end
      retval = "*"+min+".."+max
    end
    o = rule[:repetition_step]
    if o
      if o.is_a?( Parslet::Slice )
        retval = retval + "%" + o.to_s
      end
    end
  end
  retval = " " + retval if retval.length != 0
  return retval
end
rule_data(data=nil) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 325
def self.rule_data data=nil
  if data
    if data.is_a? String
      s = '"' + data + '"'
    else
      s = data.pretty_print_inspect
    end
    return elide(s)
  end
  #else
  return nil
end
rule_def(type, jcr) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 354
def self.rule_def type, jcr
  s = ""
  case type
    when "value"
      s = elide(value_to_s(jcr))
    when "member"
      s = elide(member_to_s(jcr))
    when "object"
      s = elide(object_to_s(jcr))
    when "object group"
      s = elide(group_to_s(jcr))
    when "array"
      s = elide(array_to_s(jcr))
    when "array group"
      s = elide(array_to_s(jcr))
    when "group"
      s = elide(group_to_s(jcr))
    else
      s = "** unknown rule **"
  end
  return "#{type} definition << #{s} >>"
end
rule_to_s( rule, shallow=true) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 471
def self.rule_to_s( rule, shallow=true)
  if rule[:rule_name]
    if rule[:primitive_rule]
      retval = "$#{rule[:rule_name].to_s} =: #{ruletype_to_s( rule, shallow )}"
    else
      retval = "$#{rule[:rule_name].to_s} = #{ruletype_to_s( rule, shallow )}"
    end
  else
    retval = ruletype_to_s( rule, shallow )
  end
  return retval
end
rules_to_s( rules, shallow=true) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 509
def self.rules_to_s( rules, shallow=true)
  retval = ""
  rules.each do |rule|
    if rule[:rule_name]
      next
    elsif rule[:choice_combiner]
      retval = retval + " | "
    elsif rule[:sequence_combiner]
      retval = retval + " , "
    end
    retval = retval + rule_to_s( rule, shallow ) + repetitions_to_s( rule )
  end
  return retval
end
ruletype_to_s( rule, shallow=true ) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 484
def self.ruletype_to_s( rule, shallow=true )

  if rule[:primitive_rule]
    retval = value_to_s( rule[:primitive_rule] )
  elsif rule[:member_rule]
    retval = member_to_s( rule[:member_rule], shallow )
  elsif rule[:object_rule]
    retval = object_to_s( rule[:object_rule], shallow )
  elsif rule[:array_rule]
    retval = array_to_s( rule[:array_rule], shallow )
  elsif rule[:group_rule]
    retval = group_to_s( rule[:group_rule], shallow )
  elsif rule[:target_rule_name]
    retval = target_to_s( rule[:target_rule_name] )
  elsif rule[:rule_name]
    retval = "rule: #{rule[:rule_name].to_s}"
  elsif rule[:rule]
    retval = rule_to_s( rule[:rule], shallow )
  else
    retval = "** unknown rule definition ** #{rule}"
  end
  return retval

end
slice_to_s(slice) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 435
def self.slice_to_s slice
  s = find_first_slice( slice )
  if s.is_a? Parslet::Slice
    pos = s.line_and_column
    retval = "'#{s.inspect}' ( line #{pos[0]} column #{pos[1]} )"
  else
    retval = slice.to_s
  end
  retval
end
target_to_s( jcr ) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 542
def self.target_to_s( jcr )
  return annotations_to_s( jcr[:annotations] ) + "$" + jcr[:rule_name].to_s
end
trace(econs, message, data = nil) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 338
def self.trace econs, message, data = nil
  if econs.trace
    if data
      message = "#{message} data: #{rule_data( data )}"
    end
    last = econs.trace_stack.last
    puts "[ depth=#{econs.trace_stack.length}:#{trace_coord(econs)} ] #{message}"
  end
end
trace_coord(econs) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 348
def self.trace_coord econs
  last = econs.trace_stack.last
  pos = "#{last.line_and_column}" if last
  return "pos=#{pos}"
end
trace_def(econs, type, jcr, data) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 377
def self.trace_def econs, type, jcr, data
  if econs.trace
    s = ""
    case type
      when "value"
        s = elide( value_to_s( jcr ) )
      when "member"
        s = elide( member_to_s( jcr  ) )
      when "object"
        s = elide( object_to_s( jcr ) )
      when "object group"
        s = elide( group_to_s( jcr ) )
      when "array"
        s = elide( array_to_s( jcr ) )
      when "array group"
        s = elide( array_to_s( jcr ) )
      when "group"
        s = elide( group_to_s( jcr ) )
      else
        s = "** unknown rule **"
    end
    trace( econs, rule_def( type, jcr ) )
  end
end
trace_eval(econs, message, evaluation, jcr, data, type) click to toggle source
# File lib/jcr/evaluate_rules.rb, line 402
def self.trace_eval econs, message, evaluation, jcr, data, type
  if evaluation.success
    econs.report_success
    trace( econs, "#{message} evaluation is true" )
  else
    failure = Failure.new( data, jcr, type, evaluation, econs.trace_stack.length )
    econs.report_failure( failure )
    trace( econs, "#{message} evaluation failed: #{evaluation.reason}")
  end
end
value_to_s( jcr, shallow=true ) click to toggle source
# File lib/jcr/evaluate_value_rules.rb, line 408
def self.value_to_s( jcr, shallow=true )

  rules, annotations = get_rules_and_annotations( jcr )

  rule = rules[ 0 ]
  retval = ""
  case

    when rule[:any]
      retval =  "any"

    when rule[:integer_v]
      retval =  rule[:integer_v].to_s
    when rule[:integer]
      retval =  rule[:integer].to_s.to_i
    when rule[:integer_min],rule[:integer_max]
      min = "-INF"
      max = "INF"
      min = rule[:integer_min].to_s.to_i if rule[:integer_min]
      max = rule[:integer_max].to_s.to_i if rule[:integer_max]
      retval =  "#{min}..#{max}"
    when rule[:sized_int_v]
      retval =  "int" + rule[:sized_int_v][:bits].to_s
    when rule[:sized_uint_v]
      retval =  "uint" + rule[:sized_uint_v][:bits].to_s

    when rule[:double_v]
      retval =  rule[:double_v].to_s
    when rule[:float_v]
      retval =  rule[:float_v].to_s
    when rule[:float]
      retval =  rule[:float].to_s.to_f
    when rule[:float_min],rule[:float_max]
      min = "-INF"
      max = "INF"
      min = rule[:float_min].to_s.to_f if rule[:float_min]
      max = rule[:float_max].to_s.to_f if rule[:float_max]
      retval =  "#{min}..#{max}"

    when rule[:true_v]
      retval =  "true"
    when rule[:false_v]
      retval =  "false"
    when rule[:boolean_v]
      retval =  "boolean"

    when rule[:string]
      retval =  "string"
    when rule[:q_string]
      retval =  %Q|"#{rule[:q_string].to_s}"|

    when rule[:regex]
      retval =  "/#{rule[:regex].to_s}/"

    when rule[:ipv4]
      retval =  "ipv4"
    when rule[:ipv6]
      retval =  "ipv6"

    when rule[:fqdn]
      retval =  "fqdn"
    when rule[:idn]
      retval =  "idn"

    when rule[:uri]
      if rule[:uri].is_a? Hash
        retval =  "uri..#{rule[:uri][:uri_scheme].to_s}"
      else
        retval =  "uri"
      end

    when rule[:email]
      retval =  "email"

    when rule[:phone]
      retval =  "phone"

    when rule[:hex]
      retval =  "hex"
    when rule[:base32hex]
      retval =  "base32hex"
    when rule[:base64url]
      retval =  "base64url"
    when rule[:base64]
      retval =  "base64"

    when rule[:datetime]
      retval =  "datetime"
    when rule[:date]
      retval =  "date"
    when rule[:time]
      retval =  "time"

    when rule[:null]
      retval =  "null"

    when rule[:group_rule]
      retval =  group_to_s( rule[:group_rule], shallow )

    else
      retval =  "** unknown value rule **"
  end
  return annotations_to_s( annotations ) + retval.to_s
end