Module: Ekylibre::Record::SelectsAmongAll::ClassMethods

Defined in:
lib/ekylibre/record/selects_among_all.rb

Instance Method Summary collapse

Instance Method Details

#selects_among_all(*columns) ⇒ Object

Manage


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
48
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ekylibre/record/selects_among_all.rb', line 9

def selects_among_all(*columns)
  options = columns.extract_options!

  columns = [:by_default] if columns.empty?
  code  = ''

  scope = table_name.classify.constantize.name # "self.class"
  scope << ".#{options[:subset]}" if options[:subset]
  scope_columns = []
  if s = options[:scope]
    s = [s] if s.is_a?(Symbol)
    unless s.is_a?(Symbol) || s.is_a?(Array)
      raise ArgumentError, 'Scope must be given as a Symbol or an Array of Symbol'
    end
    scope << '.where(' + s.collect do |c|
      scope_columns << c.to_sym
      "#{c}: self.#{c}"
    end.join(', ') + ')'
  end

  columns.each do |column|
    code << "before_save(:set_#{column}_if_first, on: :create)\n"
    code << "before_save(:set_#{column}_if_alone, on: :update)\n"
    code << "after_save(:ensure_#{column}_uniqueness)\n"

    pode = "self.update_column(:#{column}, true)\n"
    code << "def set_#{column}\n"
    if options[:if]
      code << "  if self.#{options[:if]}\n"
      code << pode.dig(2)
      code << "  else\n"
      code << "    return false\n"
      code << "  end\n"
    else
      code << pode.dig
    end
    code << "end\n"

    pode = "self.update_attributes!(#{column}: true)\n"
    code << "def set_#{column}!\n"
    if options[:if]
      code << "  if self.#{options[:if]}\n"
      code << pode.dig(2)
      code << "  else\n"
      code << "    fail 'Cannot selects #{column}'\n"
      code << "  end\n"
    else
      code << pode.dig
    end
    code << "end\n"

    pode = "self.#{column} = true unless #{scope}.where(#{column}: true).any?\n"
    code << "def set_#{column}_if_first\n"
    if options[:if]
      code << "  if self.#{options[:if]}\n"
      code << pode.dig(2)
      code << "  end\n"
    else
      code << pode.dig
    end
    code << "end\n"

    pode << "self.#{column} = true unless #{scope}.where(#{column}: true).where.not(id: self.id).any?\n"
    code << "def set_#{column}_if_alone\n"
    if options[:if]
      code << "  if self.#{options[:if]}\n"
      code << pode.dig(2)
      code << "  end\n"
    else
      code << pode.dig
    end
    code << "end\n"

    pode = "if self.#{column}?\n"
    pode << "  #{scope}.where(#{column}: true).where.not(id: self.id).update_all(#{column}: false)\n"
    pode << "end\n"
    code << "def ensure_#{column}_uniqueness\n"
    if options[:if]
      code << "  if self.#{options[:if]}\n"
      code << pode.dig(2)
      code << "  end\n"
    else
      code << pode.dig
    end
    code << "end\n"

    code << "def self.#{column}(" + scope_columns.collect { |c| "#{c} = nil" }.join(', ') + ")\n"
    if scope_columns.any?
      code << '  if ' + scope_columns.collect { |c| "#{c}.nil?" }.join(' or ') + "\n"
      code << "    fail ArgumentError, '#{scope_columns.size} arguments expected: " + scope_columns.join(', ') + "'\n"
      code << "  end\n"
    end
    code << '  self.find_by(' + scope_columns.collect { |c| "#{c}: #{c}, " }.join + "#{column}: true)\n"
    code << "end\n"
  end

  class_eval code
end