Commit f83ac4db9062a997faf339fefb59e0bf046c271b

Authored by AntonioTerceiro
1 parent 63f3d444

ActionItem21: moving filesystem-like behaviour from Category class into lib/acts…

…_as_filesystem.rb. All tests for Category still passing.



git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@937 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing 2 changed files with 132 additions and 103 deletions   Show diff stats
app/models/category.rb
... ... @@ -14,113 +14,11 @@ class Category < ActiveRecord::Base
14 14 end
15 15 end
16 16  
17   - acts_as_tree :order => 'name'
18   -
19   - # calculates the full name of a category by accessing the name of all its
20   - # ancestors.
21   - #
22   - # If you have this category hierarchy:
23   - # Category "A"
24   - # Category "B"
25   - # Category "C"
26   - #
27   - # Then Category "C" will have "A/B/C" as its full name.
28   - def full_name(sep = '/')
29   - my_name = self.name ? self.name : '?'
30   - self.parent ? (self.parent.full_name(sep) + sep + my_name) : (my_name)
31   - end
32   -
33   - # calculates the level of the category in the category hierarchy. Top-level
34   - # categories have level 0; the children of the top-level categories have
35   - # level 1; the children of categories with level 1 have level 2, and so on.
36   - #
37   - # A level 0
38   - # / \
39   - # B C level 1
40   - # / \ / \
41   - # E F G H level 2
42   - # ...
43   - def level
44   - self.parent ? (self.parent.level + 1) : 0
45   - end
46   -
47   - # Is this category a top-level category?
48   - def top_level?
49   - self.parent.nil?
50   - end
51   -
52   - # Is this category a leaf in the hierarchy tree of categories?
53   - #
54   - # Being a leaf means that this category has no subcategories.
55   - def leaf?
56   - self.children.empty?
57   - end
58   -
59 17 # Finds all top level categories for a given environment.
60 18 def self.top_level_for(environment)
61 19 self.find(:all, :conditions => ['parent_id is null and environment_id = ?', environment.id ])
62 20 end
63 21  
64   - # used to know when to trigger batch renaming
65   - attr_accessor :recalculate_path
66   -
67   - # sets the name of the category. Also sets #slug accordingly.
68   - def name=(value)
69   - if self.name != value
70   - self.recalculate_path = true
71   - end
72   -
73   - self[:name] = value
74   - unless self.name.blank?
75   - # FIXME encapsulate this patter (transliterate -> downcase -> gsub ...)
76   - # in a String method, say, to_slug
77   - self.slug = self.name.transliterate.downcase.gsub( /[^-a-z0-9~\s\.:;+=_]/, '').gsub(/[\s\.:;=_+]+/, '-').gsub(/[\-]{2,}/, '-').to_s
78   - end
79   - end
80   -
81   - # sets the slug of the category. Also sets the path with the new slug value.
82   - def slug=(value)
83   - self[:slug] = value
84   - unless self.slug.blank?
85   - self.path = self.calculate_path
86   - end
87   - end
88   -
89   - # calculates the full path to this category using parent's path.
90   - def calculate_path
91   - if self.top_level?
92   - self.slug
93   - else
94   - self.parent.calculate_path + "/" + self.slug
95   - end
96   - end
97   -
98   - # calculate the right path
99   - before_create do |cat|
100   - if cat.path == cat.slug && (! cat.top_level?)
101   - cat.path = cat.calculate_path
102   - end
103   - end
104   -
105   - # when renaming a category, all children categories must have their paths
106   - # recalculated
107   - after_update do |cat|
108   - if cat.recalculate_path
109   - cat.children.each do |item|
110   - item.path = item.calculate_path
111   - item.recalculate_path = true
112   - item.save!
113   - end
114   - end
115   - cat.recalculate_path = false
116   - end
117   -
118   - def top_ancestor
119   - self.top_level? ? self : self.parent.top_ancestor
120   - end
121   -
122   - def explode_path
123   - path.split(/\//)
124   - end
  22 + acts_as_filesystem
125 23  
126 24 end
... ...
lib/acts_as_filesystem.rb 0 → 100644
... ... @@ -0,0 +1,131 @@
  1 +module ActsAsFileSystem
  2 +
  3 + module ClassMethods
  4 +
  5 + # Declares the ActiveRecord model to acts like a filesystem: objects are
  6 + # arranged in a tree (liks acts_as_tree), and . The underlying table must
  7 + # have the following fields:
  8 + #
  9 + # * name (+:string+) - the title of the object
  10 + # * slug (+:string+)- the title turned in a URL-friendly string (downcased,
  11 + # non-ascii chars transliterated into ascii, all sequences of
  12 + # non-alphanumericd characters changed into dashed)
  13 + # * path (+:text+)- stores the full path of the object (the full path of
  14 + # the parent, a "/" and the slug of the object)
  15 + def acts_as_filesystem
  16 +
  17 + include ActsAsFileSystem::InstanceMethods
  18 +
  19 + # a filesystem is a tree
  20 + acts_as_tree :order => 'name'
  21 +
  22 + # calculate the right path
  23 + before_create do |record|
  24 + if record.path == record.slug && (! record.top_level?)
  25 + record.path = record.calculate_path
  26 + end
  27 + end
  28 +
  29 + # when renaming a category, all children categories must have their paths
  30 + # recalculated
  31 + after_update do |record|
  32 + if record.recalculate_path
  33 + record.children.each do |item|
  34 + item.path = item.calculate_path
  35 + item.recalculate_path = true
  36 + item.save!
  37 + end
  38 + end
  39 + record.recalculate_path = false
  40 + end
  41 +
  42 + end
  43 + end
  44 +
  45 + module InstanceMethods
  46 + # used to know when to trigger batch renaming
  47 + attr_accessor :recalculate_path
  48 +
  49 + # calculates the full name of a category by accessing the name of all its
  50 + # ancestors.
  51 + #
  52 + # If you have this category hierarchy:
  53 + # Category "A"
  54 + # Category "B"
  55 + # Category "C"
  56 + #
  57 + # Then Category "C" will have "A/B/C" as its full name.
  58 + def full_name(sep = '/')
  59 + my_name = self.name ? self.name : '?'
  60 + self.parent ? (self.parent.full_name(sep) + sep + my_name) : (my_name)
  61 + end
  62 +
  63 + # calculates the level of the category in the category hierarchy. Top-level
  64 + # categories have level 0; the children of the top-level categories have
  65 + # level 1; the children of categories with level 1 have level 2, and so on.
  66 + #
  67 + # A level 0
  68 + # / \
  69 + # B C level 1
  70 + # / \ / \
  71 + # E F G H level 2
  72 + # ...
  73 + def level
  74 + self.parent ? (self.parent.level + 1) : 0
  75 + end
  76 +
  77 + # Is this category a top-level category?
  78 + def top_level?
  79 + self.parent.nil?
  80 + end
  81 +
  82 + # Is this category a leaf in the hierarchy tree of categories?
  83 + #
  84 + # Being a leaf means that this category has no subcategories.
  85 + def leaf?
  86 + self.children.empty?
  87 + end
  88 +
  89 + # sets the name of the category. Also sets #slug accordingly.
  90 + def name=(value)
  91 + if self.name != value
  92 + self.recalculate_path = true
  93 + end
  94 +
  95 + self[:name] = value
  96 + unless self.name.blank?
  97 + # FIXME encapsulate this pattern (transliterate -> downcase -> gsub
  98 + # ...) in a String method, say, to_slug
  99 + self.slug = self.name.transliterate.downcase.gsub( /[^-a-z0-9~\s\.:;+=_]/, '').gsub(/[\s\.:;=_+]+/, '-').gsub(/[\-]{2,}/, '-').to_s
  100 + end
  101 + end
  102 +
  103 + # sets the slug of the category. Also sets the path with the new slug value.
  104 + def slug=(value)
  105 + self[:slug] = value
  106 + unless self.slug.blank?
  107 + self.path = self.calculate_path
  108 + end
  109 + end
  110 +
  111 + # calculates the full path to this category using parent's path.
  112 + def calculate_path
  113 + if self.top_level?
  114 + self.slug
  115 + else
  116 + self.parent.calculate_path + "/" + self.slug
  117 + end
  118 + end
  119 +
  120 + def top_ancestor
  121 + self.top_level? ? self : self.parent.top_ancestor
  122 + end
  123 +
  124 + def explode_path
  125 + path.split(/\//)
  126 + end
  127 + end
  128 +end
  129 +
  130 +ActiveRecord::Base.extend ActsAsFileSystem::ClassMethods
  131 +
... ...