| 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 |