Module: Glue::Orderable

Includes:
Aspects
Defined in:
lib/glue/orderable.rb

Overview

Attach list/ordering methods to the enchanted class.

Comments

If you use the scope option, you have to set he parent (scope) of the object before inserting to have correct ordering.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included_with_parameters(base, opt) ⇒ Object



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
# File 'lib/glue/orderable.rb', line 16

def self.included_with_parameters(base, opt)

  # The attribute to use to keep the position.
  
  opt_position = opt.fetch(:position, 'position')

  # The type of the position attribute.
  
  opt_type = opt.fetch(:type, Fixnum)

  # A user defined condition.
  
  opt_condition = opt[:condition]

  # A condition based on a key field (?)
  
  opt_scope = opt[:scope]

  # clean scope field.
  
  if opt_scope
    if opt_scope.to_s !~ /_oid$/
      opt_scope = "#{opt_scope}_oid".to_sym
    else
      opt_scope = opt_scope.to_sym
    end
  end

  base.module_eval %{
    attr_accessor :#{opt_position}, #{opt_type}

    def orderable_attribute
      #{opt_position.inspect}
    end
        
    def orderable_position
      @#{opt_position}
    end

    def orderable_position= (pos)
      @#{opt_position} = pos
    end

    def orderable_type
      #{opt_type}
    end
 
    def orderable_scope
      #{opt_scope.inspect}
    end

    def orderable_condition
      scope = orderable_scope
      if scope
        scope_value = send(scope)
        scope = scope_value ? "\#{scope} = \#{scope_value}" : "\#{scope} IS NULL"
      end
      return [ #{opt_condition.inspect}, scope ].compact
    end
  }

end

Instance Method Details

#add_toObject



154
155
156
# File 'lib/glue/orderable.rb', line 154

def add_to
  # TODO
end

#add_to_bottomObject



150
151
152
# File 'lib/glue/orderable.rb', line 150

def add_to_bottom
  self.orderable_position = bottom_position + 1
end

#add_to_topObject



146
147
148
# File 'lib/glue/orderable.rb', line 146

def add_to_top
  increment_position_of_all_items
end

#bottom?Boolean Also known as: last?

Returns:

  • (Boolean)


190
191
192
# File 'lib/glue/orderable.rb', line 190

def bottom?
  self.orderable_position == bottom_position
end

#bottom_itemObject



177
178
179
180
181
182
# File 'lib/glue/orderable.rb', line 177

def bottom_item
  pos = orderable_attribute
  con = orderable_condition
  con = con.empty? ? nil : con.join(' AND ')
  self.class.one(:condition => con, :order => "#{pos} DESC", :limit => 1)
end

#bottom_positionObject



205
206
207
208
# File 'lib/glue/orderable.rb', line 205

def bottom_position
  item = bottom_item
  item ? (item.orderable_position || 0) : 0
end

#decrement_positionObject



200
201
202
203
# File 'lib/glue/orderable.rb', line 200

def decrement_position
  self.orderable_position -= 1
  update_attribute(self.orderable_attribute)
end

#decrement_position_of_lower_itemsObject



233
234
235
236
237
# File 'lib/glue/orderable.rb', line 233

def decrement_position_of_lower_items
  pos = orderable_attribute
  con = orderable_condition + [ "#{pos} > #{orderable_position}" ]
  self.class.update "#{pos}=(#{pos} - 1)",  :condition => con.join(' AND ')
end

#higher_itemObject Also known as: previous_item



158
159
160
161
162
# File 'lib/glue/orderable.rb', line 158

def higher_item
  pos = orderable_attribute
  con = orderable_condition + [ "#{pos} = #{orderable_position - 1}" ]
  self.class.one( :condition => con.join(' AND ') )
end

#increment_positionObject



195
196
197
198
# File 'lib/glue/orderable.rb', line 195

def increment_position
  self.orderable_position += 1
  update_attribute(self.orderable_attribute)
end

#increment_position_of_all_itemsObject



226
227
228
229
230
231
# File 'lib/glue/orderable.rb', line 226

def increment_position_of_all_items
  pos = orderable_attribute
  con = orderable_condition
  con = con.empty? ? nil : con.join(' AND ')
  self.class.update "#{pos}=(#{pos} + 1)", :condition => con 
end

#increment_position_of_higher_itemsObject



220
221
222
223
224
# File 'lib/glue/orderable.rb', line 220

def increment_position_of_higher_items
  pos = orderable_attribute
  con = orderable_condition + [ "#{pos} < #{orderable_position}" ]
  self.class.update "#{pos}=(#{pos} + 1)",  :condition => con.join(' AND ')
end

#lower_itemObject Also known as: next_item



165
166
167
168
169
# File 'lib/glue/orderable.rb', line 165

def lower_item
  pos = orderable_attribute
  con = orderable_condition + [ "#{pos} = #{orderable_position + 1}" ]
  self.class.one( :condition => con.join(' AND ') )
end

#move_higherObject

Move higher.



84
85
86
87
88
89
90
91
# File 'lib/glue/orderable.rb', line 84

def move_higher
  if higher = higher_item
    self.class.transaction do
      higher.increment_position
      decrement_position
    end
  end
end

#move_lowerObject

Move lower.



95
96
97
98
99
100
101
102
# File 'lib/glue/orderable.rb', line 95

def move_lower
  if lower = lower_item
    self.class.transaction do
      lower.decrement_position
      increment_position
    end
  end
end

#move_to(dest_position) ⇒ Object

Move to a specific position.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/glue/orderable.rb', line 124

def move_to(dest_position)
  return if self.orderable_position == dest_position

  pos = orderable_attribute
  con = orderable_condition

  self.class.transaction do
    if orderable_position < dest_position
      adj = "#{pos} = #{pos} - 1"
      con = con + [ "#{pos} > #{orderable_position}", "#{pos} <= #{dest_position}" ]
    else
      adj = "#{pos} = #{pos} + 1"
      con = con + [ "#{pos} < #{orderable_position}", "#{pos} >= #{dest_position}" ]
    end
    self.class.update( adj, :condition => con.join(' AND ') )
    self.orderable_position = dest_position
    update_attribute(orderable_attribute)
  end

  self
end

#move_to_bottomObject

Move to the bottom.



115
116
117
118
119
120
# File 'lib/glue/orderable.rb', line 115

def move_to_bottom
  self.class.transaction do
    decrement_position_of_lower_items
    set_bottom_position
  end
end

#move_to_topObject

Move to the top.



106
107
108
109
110
111
# File 'lib/glue/orderable.rb', line 106

def move_to_top
  self.class.transaction do
    increment_position_of_higher_items
    set_top_position
  end
end

#set_bottom_positionObject



215
216
217
218
# File 'lib/glue/orderable.rb', line 215

def set_bottom_position
  self.orderable_position = bottom_position + 1
  update_attribute(orderable_attribute)
end

#set_top_positionObject



210
211
212
213
# File 'lib/glue/orderable.rb', line 210

def set_top_position
  self.orderable_position = 1
  update_attribute(orderable_attribute)
end

#top?Boolean Also known as: first?

Returns:

  • (Boolean)


185
186
187
# File 'lib/glue/orderable.rb', line 185

def top?
  self.orderable_position == 1
end

#top_itemObject Also known as: first_item



172
173
174
# File 'lib/glue/orderable.rb', line 172

def top_item
  # TODO
end