Module: GrapeHasScope

Included in:
Grape::Endpoint
Defined in:
lib/grape_has_scope.rb

Constant Summary collapse

TRUE_VALUES =
["true", true, "1", 1]
ALLOWED_TYPES =
{
  :array   => [ Array ],
  :hash    => [ Hash ],
  :boolean => [ Object ],
  :default => [ String, Numeric ]
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



11
12
13
14
15
# File 'lib/grape_has_scope.rb', line 11

def self.included(base)
  base.class_eval do
    class_attribute :scopes_configuration
  end
end

Instance Method Details

#applicable?(string_proc_or_symbol, expected) ⇒ Boolean

Evaluates the scope options :if or :unless. Returns true if the proc method, or string evals to the expected value.

Returns:

  • (Boolean)


129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/grape_has_scope.rb', line 129

def applicable?(string_proc_or_symbol, expected) #:nodoc:
  case string_proc_or_symbol
    when String
      eval(string_proc_or_symbol) == expected
    when Proc
      string_proc_or_symbol.call(self) == expected
    when Symbol
      send(string_proc_or_symbol) == expected
    else
      true
  end
end

#apply_scope_to_action?(options) ⇒ Boolean

Given an options with :only and :except arrays, check if the scope can be performed in the current action.

Returns:

  • (Boolean)


117
118
119
120
121
122
123
124
125
# File 'lib/grape_has_scope.rb', line 117

def apply_scope_to_action?(options) #:nodoc:
  return false unless applicable?(options[:if], true) && applicable?(options[:unless], false)

  if options[:only].empty?
    options[:except].empty? || !options[:except].include?(action_name.to_sym)
  else
    options[:only].include?(action_name.to_sym)
  end
end

#apply_scopes(target, hash = params) ⇒ Object

Receives an object where scopes will be applied to.

class GraduationsController < InheritedResources::Base
  has_scope :featured, :type => true, :only => :index
  has_scope :by_degree, :only => :index

  def index
    @graduations = apply_scopes(Graduation).all
  end
end


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
# File 'lib/grape_has_scope.rb', line 54

def apply_scopes(target, hash=params)
  return target unless scopes_configuration

  self.class.scopes_configuration.each do |scope, options|
    next unless apply_scope_to_action?(options)
    key = options[:as]

    if hash.key?(key)
      value, call_scope = hash[key], true
    elsif options.key?(:default)
      value, call_scope = options[:default], true
      value = value.call(self) if value.is_a?(Proc)
    end

    value = parse_value(options[:type], key, value)
    value = normalize_blanks(value)

    if call_scope && (value.present? || options[:allow_blank])
      current_scopes[key] = value
      target = call_scope_by_type(options[:type], scope, target, value, options)
    end
  end

  target
end

#call_scope_by_type(type, scope, target, value, options) ⇒ Object

Call the scope taking into account its type.



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/grape_has_scope.rb', line 102

def call_scope_by_type(type, scope, target, value, options) #:nodoc:
  block = options[:block]

  if type == :boolean
    block ? block.call(self, target) : target.send(scope)
  elsif value && options.key?(:using)
    value = value.values_at(*options[:using])
    block ? block.call(self, target, value) : target.send(scope, *value)
  else
    block ? block.call(self, target, value) : target.send(scope, value)
  end
end

#current_scopesObject

Returns the scopes used in this action.



143
144
145
# File 'lib/grape_has_scope.rb', line 143

def current_scopes
  @current_scopes ||= {}
end

#has_scope(*scopes, &block) ⇒ Object



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
# File 'lib/grape_has_scope.rb', line 17

def has_scope(*scopes, &block)
  options = scopes.extract_options!
  options.symbolize_keys!
  options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as, :using, :allow_blank)

  if options.key?(:using)
    if options.key?(:type) && options[:type] != :hash
      raise "You cannot use :using with another :type different than :hash"
    else
      options[:type] = :hash
    end

    options[:using] = Array(options[:using])
  end

  options[:only]   = Array(options[:only])
  options[:except] = Array(options[:except])

  self.class.scopes_configuration = (self.class.scopes_configuration || {}).dup

  scopes.each do |scope|
    self.class.scopes_configuration[scope] ||= { :as => scope, :type => :default, :block => block }
    self.class.scopes_configuration[scope] = self.class.scopes_configuration[scope].merge(options)
  end
end

#normalize_blanks(value) ⇒ Object

Screens pseudo-blank params.



90
91
92
93
94
95
96
97
98
99
# File 'lib/grape_has_scope.rb', line 90

def normalize_blanks(value) #:nodoc:
  return value if value.nil?
  if value.is_a?(Array)
    value.select { |v| v.present? }
  elsif value.is_a?(Hash)
    value.select { |k, v| normalize_blanks(v).present? }.with_indifferent_access
  else
    value
  end
end

#parse_value(type, key, value) ⇒ Object

Set the real value for the current scope if type check.



81
82
83
84
85
86
87
# File 'lib/grape_has_scope.rb', line 81

def parse_value(type, key, value) #:nodoc:
  if type == :boolean
    TRUE_VALUES.include?(value)
  elsif value && ALLOWED_TYPES[type].any?{ |klass| value.is_a?(klass) }
    value
  end
end