Class: Reading::Stats::Operation

Inherits:
Object
  • Object
show all
Defined in:
lib/reading/stats/operation.rb

Overview

The beginning of a query which specifies what it does, e.g. “average rating” or “total amount”.

Class Method Summary collapse

Class Method Details

.apply_to_inner_items(grouped_items) {|Array<Item>| ... } ⇒ Object

A recursive method that applies the block to the leaf nodes (arrays of Items) of the given hash of grouped items.

Parameters:

  • grouped_items (Hash)

Yields:



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/reading/stats/operation.rb', line 53

def self.apply_to_inner_items(grouped_items, &block)
  if grouped_items.values.first.is_a? Array
    grouped_items.transform_values! { |inner_items|
      yield inner_items
    }
  else # It's a Hash, so go one level deeper.
    grouped_items.each do |group_name, grouped|
      apply_to_inner_items(grouped, &block)
    end
  end
end

.execute(input, grouped_items, result_formatters) ⇒ Object

Determines which operation is contained in the given input, and then runs it to get the result. For the operations and their actions, see the constants below.

Parameters:

  • input (String)

    the query string.

  • grouped_items (Hash{Symbol => Array<Item>})

    if no group was used, the hash is just { all: items }

  • result_formatters (Hash{Symbol => Proc})

    to alter the appearance of results. Keys should be from among the keys of Operation::ACTIONS.

Returns:

  • (Object)

    the return value of the action; if items are grouped then a hash is returned with the same keys as grouped_items, otherwise just the array of all results (not grouped) is returned.

Raises:



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/reading/stats/operation.rb', line 19

def self.execute(input, grouped_items, result_formatters)
  REGEXES.each do |key, regex|
    match = input.match(regex)

    if match
      if match[:number_arg]
        number_arg = Integer(match[:number_arg], exception: false) ||
          (raise InputError, "Argument must be an integer. Example: top 5 ratings")
      end

      results = apply_to_inner_items(grouped_items) do |inner_items|
        result = ACTIONS[key].call(inner_items, number_arg)

        default_formatter = :itself.to_proc # just the result itself
        result_formatter = result_formatters[key] || default_formatter

        result_formatter.call(result)
      end

      if results.keys == [:all] # no groupings
        return results[:all]
      else
        return results
      end
    end
  end

  raise InputError, "No valid operation in stats query \"#{input}\""
end