Module: CommandSearch::Memory

Defined in:
lib/command_search/memory.rb

Class Method Summary collapse

Class Method Details

.build_query(ast, fields, command_types = {}) ⇒ Object



121
122
123
# File 'lib/command_search/memory.rb', line 121

def build_query(ast, fields, command_types = {})
  proc { |x| check(x, ast, fields, command_types) }
end

.check(item, ast, fields, command_types) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/command_search/memory.rb', line 89

def check(item, ast, fields, command_types)
  field_vals = fields.map { |x| item[x] || item[x.to_s] || item[x.to_sym] }.compact
  ast_array = ast.is_a?(Array) ? ast : [ast]
  ast_array.all? do |node|
    val = node[:value]
    case node[:nest_type]
    when nil
      if node[:type] == :quoted_str
        regex = /\b#{Regexp.escape(val)}\b/
        if val[/(^\W)|(\W$)/]
          head_border = '(?<=^|[^:+\w])'
          tail_border = '(?=$|[^:+\w])'
          regex = Regexp.new(head_border + Regexp.escape(val) + tail_border)
        end
        field_vals.any? { |x| x.to_s[regex] }
      else
        field_vals.any? { |x| x.to_s[/#{Regexp.escape(val)}/i] }
      end
    when :colon
      command_check(item, val, command_types)
    when :compare
      compare_check(item, node, command_types)
    when :pipe
      val.any? { |v| check(item, v, fields, command_types) }
    when :minus
      val.none? { |v| check(item, v, fields, command_types) }
    when :paren
      val.all? { |v| check(item, v, fields, command_types) }
    end
  end
end

.command_check(item, val, command_types) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/command_search/memory.rb', line 7

def command_check(item, val, command_types)
  cmd = val[0][:value].to_sym
  cmd_search = val[1][:value]
  raw_cmd_type = [command_types[cmd]].flatten
  allow_existence_boolean = raw_cmd_type.include?(:allow_existence_boolean)
  cmd_type = (raw_cmd_type - [:allow_existence_boolean]).first
  if cmd_type == Boolean
    if cmd_search[/true/i]
      item[cmd]
    else
      item[cmd] == false
    end
  elsif allow_existence_boolean && (cmd_search[/true/i] || cmd_search[/false/i])
    if cmd_search[/true/i]
      item[cmd]
    else
      item[cmd] == nil
    end
  elsif !item.key?(cmd)
    return false
  elsif [Date, Time, DateTime].include?(cmd_type)
    item_time = item[cmd].to_time
    if cmd_search == cmd_search.to_i.to_s
      Time.new(cmd_search) <= item_time && item_time < Time.new(cmd_search.to_i + 1)
    else
      input_times = Chronic.parse(cmd_search, { guess: nil })
      input_times.first <= item_time && item_time < input_times.last
    end
  elsif val[1][:type] == :quoted_str
    regex = /\b#{Regexp.escape(cmd_search)}\b/
    regex = /\A\Z/ if cmd_search == ''
    if cmd_search[/(^\W)|(\W$)/]
      head_border = '(?<=^|[^:+\w])'
      tail_border = '(?=$|[^:+\w])'
      regex = Regexp.new(head_border + Regexp.escape(cmd_search) + tail_border)
    end
    item[cmd][regex]
  else
    item[cmd].to_s[/#{Regexp.escape(cmd_search)}/i]
  end
end

.compare_check(item, node, command_types) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/command_search/memory.rb', line 49

def compare_check(item, node, command_types)
  children = node[:value]
  cmd = children.find { |c| command_types[c[:value].to_sym] }
  raw_cmd_type = [command_types[cmd[:value].to_sym]].flatten
  cmd_type = (raw_cmd_type - [:allow_existence_boolean]).first

  args = children.map do |child|
    child_val = child[:value]
    item_val = item[child_val.to_s] || item[child_val.to_sym]
    item_val ||= child_val unless child == cmd
    next unless item_val
    next item_val.to_time if child == cmd && [Date, Time, DateTime].include?(cmd_type)
    next item_val if child == cmd
    if [Date, Time, DateTime].include?(cmd_type)
      date_start_map = {
        '<' => :start,
        '>' => :end,
        '<=' => :end,
        '>=' => :start
      }
      date_pick = date_start_map[node[:nest_op]]
      time_str = item_val.gsub(/[\._-]/, ' ')

      next Time.new(time_str) if time_str == time_str.to_i.to_s

      date = Chronic.parse(time_str, { guess: nil })
      if date_pick == :start
        date.first
      else
        date.last
      end
    else
      item_val
    end
  end
  return unless args.all?
  fn = node[:nest_op].to_sym.to_proc
  fn.call(*args.map(&:to_f))
end