1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,221 @@ |
0 |
+--- |
|
1 |
+layout: default |
|
2 |
+title: Syntax Highlighting Debug |
|
3 |
+--- |
|
4 |
+{% highlight ruby linenos %} |
|
5 |
+ def rebuild_site(relative) |
|
6 |
+ puts ">>> Change Detected to: #{relative} <<<" |
|
7 |
+ IO.popen('rake generate') do |io| |
|
8 |
+ print(io.readpartial(512)) until io.eof? |
|
9 |
+ end |
|
10 |
+ puts '>>> Update Complete <<<' |
|
11 |
+ end |
|
12 |
+ |
|
13 |
+{% endhighlight %} |
|
14 |
+ |
|
15 |
+{% highlight ruby linenos %} |
|
16 |
+require 'active_support/core_ext/array' |
|
17 |
+require 'active_support/core_ext/hash/except' |
|
18 |
+require 'active_support/core_ext/object/metaclass' |
|
19 |
+ |
|
20 |
+module ActiveRecord |
|
21 |
+ module NamedScope |
|
22 |
+ extend ActiveSupport::Concern |
|
23 |
+ |
|
24 |
+ # All subclasses of ActiveRecord::Base have one named scope: |
|
25 |
+ # * <tt>scoped</tt> - which allows for the creation of anonymous \scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt> |
|
26 |
+ # |
|
27 |
+ # These anonymous \scopes tend to be useful when procedurally generating complex queries, where passing |
|
28 |
+ # intermediate values (scopes) around as first-class objects is convenient. |
|
29 |
+ # |
|
30 |
+ # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope. |
|
31 |
+ included do |
|
32 |
+ named_scope :scoped, lambda { |scope| scope } |
|
33 |
+ end |
|
34 |
+ |
|
35 |
+ module ClassMethods |
|
36 |
+ def scopes |
|
37 |
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) |
|
38 |
+ end |
|
39 |
+ |
|
40 |
+ # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, |
|
41 |
+ # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>. |
|
42 |
+ # |
|
43 |
+ # class Shirt < ActiveRecord::Base |
|
44 |
+ # named_scope :red, :conditions => {:color => 'red'} |
|
45 |
+ # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] |
|
46 |
+ # end |
|
47 |
+ # |
|
48 |
+ # The above calls to <tt>named_scope</tt> define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, |
|
49 |
+ # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>. |
|
50 |
+ # |
|
51 |
+ # Unlike <tt>Shirt.find(...)</tt>, however, the object returned by Shirt.red is not an Array; it resembles the association object |
|
52 |
+ # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>, |
|
53 |
+ # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just |
|
54 |
+ # as with the association objects, named \scopes act like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, |
|
55 |
+ # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really was an Array. |
|
56 |
+ # |
|
57 |
+ # These named \scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only. |
|
58 |
+ # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments |
|
59 |
+ # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>. |
|
60 |
+ # |
|
61 |
+ # All \scopes are available as class methods on the ActiveRecord::Base descendant upon which the \scopes were defined. But they are also available to |
|
62 |
+ # <tt>has_many</tt> associations. If, |
|
63 |
+ # |
|
64 |
+ # class Person < ActiveRecord::Base |
|
65 |
+ # has_many :shirts |
|
66 |
+ # end |
|
67 |
+ # |
|
68 |
+ # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean |
|
69 |
+ # only shirts. |
|
70 |
+ # |
|
71 |
+ # Named \scopes can also be procedural: |
|
72 |
+ # |
|
73 |
+ # class Shirt < ActiveRecord::Base |
|
74 |
+ # named_scope :colored, lambda { |color| |
|
75 |
+ # { :conditions => { :color => color } } |
|
76 |
+ # } |
|
77 |
+ # end |
|
78 |
+ # |
|
79 |
+ # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts. |
|
80 |
+ # |
|
81 |
+ # Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations: |
|
82 |
+ # |
|
83 |
+ # class Shirt < ActiveRecord::Base |
|
84 |
+ # named_scope :red, :conditions => {:color => 'red'} do |
|
85 |
+ # def dom_id |
|
86 |
+ # 'red_shirts' |
|
87 |
+ # end |
|
88 |
+ # end |
|
89 |
+ # end |
|
90 |
+ # |
|
91 |
+ # |
|
92 |
+ # For testing complex named \scopes, you can examine the scoping options using the |
|
93 |
+ # <tt>proxy_options</tt> method on the proxy itself. |
|
94 |
+ # |
|
95 |
+ # class Shirt < ActiveRecord::Base |
|
96 |
+ # named_scope :colored, lambda { |color| |
|
97 |
+ # { :conditions => { :color => color } } |
|
98 |
+ # } |
|
99 |
+ # end |
|
100 |
+ # |
|
101 |
+ # expected_options = { :conditions => { :colored => 'red' } } |
|
102 |
+ # assert_equal expected_options, Shirt.colored('red').proxy_options |
|
103 |
+ def named_scope(name, options = {}, &block) |
|
104 |
+ name = name.to_sym |
|
105 |
+ scopes[name] = lambda do |parent_scope, *args| |
|
106 |
+ Scope.new(parent_scope, case options |
|
107 |
+ when Hash |
|
108 |
+ options |
|
109 |
+ when Proc |
|
110 |
+ options.call(*args) |
|
111 |
+ end, &block) |
|
112 |
+ end |
|
113 |
+ metaclass.instance_eval do |
|
114 |
+ define_method name do |*args| |
|
115 |
+ scopes[name].call(self, *args) |
|
116 |
+ end |
|
117 |
+ end |
|
118 |
+ end |
|
119 |
+ end |
|
120 |
+ |
|
121 |
+ class Scope |
|
122 |
+ attr_reader :proxy_scope, :proxy_options, :current_scoped_methods_when_defined |
|
123 |
+ NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? many? respond_to?).to_set |
|
124 |
+ [].methods.each do |m| |
|
125 |
+ unless m =~ /^__/ || NON_DELEGATE_METHODS.include?(m.to_s) |
|
126 |
+ delegate m, :to => :proxy_found |
|
127 |
+ end |
|
128 |
+ end |
|
129 |
+ |
|
130 |
+ delegate :scopes, :with_scope, :scoped_methods, :to => :proxy_scope |
|
131 |
+ |
|
132 |
+ def initialize(proxy_scope, options, &block) |
|
133 |
+ options ||= {} |
|
134 |
+ [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] |
|
135 |
+ extend Module.new(&block) if block_given? |
|
136 |
+ unless Scope === proxy_scope |
|
137 |
+ @current_scoped_methods_when_defined = proxy_scope.send(:current_scoped_methods) |
|
138 |
+ end |
|
139 |
+ @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) |
|
140 |
+ end |
|
141 |
+ |
|
142 |
+ def reload |
|
143 |
+ load_found; self |
|
144 |
+ end |
|
145 |
+ |
|
146 |
+ def first(*args) |
|
147 |
+ if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) |
|
148 |
+ proxy_found.first(*args) |
|
149 |
+ else |
|
150 |
+ find(:first, *args) |
|
151 |
+ end |
|
152 |
+ end |
|
153 |
+ |
|
154 |
+ def last(*args) |
|
155 |
+ if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) |
|
156 |
+ proxy_found.last(*args) |
|
157 |
+ else |
|
158 |
+ find(:last, *args) |
|
159 |
+ end |
|
160 |
+ end |
|
161 |
+ |
|
162 |
+ def size |
|
163 |
+ @found ? @found.length : count |
|
164 |
+ end |
|
165 |
+ |
|
166 |
+ def empty? |
|
167 |
+ @found ? @found.empty? : count.zero? |
|
168 |
+ end |
|
169 |
+ |
|
170 |
+ def respond_to?(method, include_private = false) |
|
171 |
+ super || @proxy_scope.respond_to?(method, include_private) |
|
172 |
+ end |
|
173 |
+ |
|
174 |
+ def any? |
|
175 |
+ if block_given? |
|
176 |
+ proxy_found.any? { |*block_args| yield(*block_args) } |
|
177 |
+ else |
|
178 |
+ !empty? |
|
179 |
+ end |
|
180 |
+ end |
|
181 |
+ |
|
182 |
+ # Returns true if the named scope has more than 1 matching record. |
|
183 |
+ def many? |
|
184 |
+ if block_given? |
|
185 |
+ proxy_found.many? { |*block_args| yield(*block_args) } |
|
186 |
+ else |
|
187 |
+ size > 1 |
|
188 |
+ end |
|
189 |
+ end |
|
190 |
+ |
|
191 |
+ protected |
|
192 |
+ def proxy_found |
|
193 |
+ @found || load_found |
|
194 |
+ end |
|
195 |
+ |
|
196 |
+ private |
|
197 |
+ def method_missing(method, *args, &block) |
|
198 |
+ if scopes.include?(method) |
|
199 |
+ scopes[method].call(self, *args) |
|
200 |
+ else |
|
201 |
+ with_scope({:find => proxy_options, :create => proxy_options[:conditions].is_a?(Hash) ? proxy_options[:conditions] : {}}, :reverse_merge) do |
|
202 |
+ method = :new if method == :build |
|
203 |
+ if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) |
|
204 |
+ with_scope current_scoped_methods_when_defined do |
|
205 |
+ proxy_scope.send(method, *args, &block) |
|
206 |
+ end |
|
207 |
+ else |
|
208 |
+ proxy_scope.send(method, *args, &block) |
|
209 |
+ end |
|
210 |
+ end |
|
211 |
+ end |
|
212 |
+ end |
|
213 |
+ |
|
214 |
+ def load_found |
|
215 |
+ @found = find(:all) |
|
216 |
+ end |
|
217 |
+ end |
|
218 |
+ end |
|
219 |
+end |
|
220 |
+{% endhighlight %} |
|
0 | 221 |
\ No newline at end of file |