ScopedProxy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +18 -0
- data/Manifest.txt +7 -0
- data/README.txt +105 -0
- data/Rakefile +25 -0
- data/lib/scoped_proxy.rb +142 -0
- data/spec/scoped_proxy_spec.rb +164 -0
- data/spec/spec_helper.rb +12 -0
- metadata +70 -0
data/History.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
== 1.0.0 / 2007-12-16
|
2
|
+
|
3
|
+
First official release.
|
4
|
+
|
5
|
+
* Added default_proxy method.
|
6
|
+
|
7
|
+
* Added delegation/answer to respond_to?
|
8
|
+
|
9
|
+
== 0.5.2
|
10
|
+
|
11
|
+
Inofficial release on our blog neotrivium.com. Fixing a few bugs due to user reports.
|
12
|
+
|
13
|
+
* v0.4 Fixed a bug with scoping (another one) pointed out to me by Severin Schoepke.
|
14
|
+
Scoping will now even work in situations where an AssociationProxy sets the context.
|
15
|
+
|
16
|
+
* v0.3 Fixed a scoping bug pointed out by fractious; now scoping should work as advertised. Thanks go
|
17
|
+
to Florian Hanke for teaming up with me on this.
|
18
|
+
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
ScopedProxy
|
2
|
+
|
3
|
+
== SUMMARY
|
4
|
+
|
5
|
+
Finally, long awaited, scoped proxies as a release. Which you say. Admitted, there are about 15 plugins
|
6
|
+
that are called scoped_proxy, but only one comes with a full suite of tests that is full 40 lines longer
|
7
|
+
than the actual code. That is the scoped proxy you are looking at. It is y2k compliant and works as a gem.
|
8
|
+
Magnificent, isn't it?
|
9
|
+
|
10
|
+
This gem is all about simplicity; you won't find a whole toolbox here, just another valued screwdriver.
|
11
|
+
But we happen to encounter a lot of screws - hopefully you do too - and find this very useful. If you
|
12
|
+
want to skip all this summary that is really longer than all the other texts in this release, have a look
|
13
|
+
at the synopsis below.
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
Allows storing scopes as names; that way you can address subsets of your model space by meaningful names.
|
18
|
+
|
19
|
+
require 'scoped_proxy' # Railsers: You might want to call this in environment.rb
|
20
|
+
|
21
|
+
class User < ActiveRecord::Base
|
22
|
+
scoped_proxy :role do |role|
|
23
|
+
{
|
24
|
+
:find => { :conditions => ['role = ?', role] }
|
25
|
+
}
|
26
|
+
end
|
27
|
+
scoped_proxy :deleted, :find => {
|
28
|
+
:conditions => 'deleted_at is not null'
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
admins = User.role('admin')
|
33
|
+
admins.count # => 12
|
34
|
+
admins.find(:all) # => [ ... ]
|
35
|
+
|
36
|
+
User.deleted.count # => a number
|
37
|
+
|
38
|
+
This implementation also brings (NEW, SHINY) default proxies. That means you can have a proxy in effect
|
39
|
+
when no other proxy is in effect.
|
40
|
+
|
41
|
+
class User < ActiveRecord::Base
|
42
|
+
default_proxy :find => { :conditions => 'deleted_at is null' }
|
43
|
+
end
|
44
|
+
|
45
|
+
User.find(:all) # only finds users that aren't deleted
|
46
|
+
|
47
|
+
== REQUIREMENTS:
|
48
|
+
|
49
|
+
* gem install metaid
|
50
|
+
|
51
|
+
== TESTING
|
52
|
+
|
53
|
+
If you want to run the rspec tests, you must have a database on localhost called 'test' and a user
|
54
|
+
called 'developer' that is allowed to (write)access it. Caution: running the tests will delete at least
|
55
|
+
your 'users' table in said database. But I hope you wouldn't run this on production, nor call your
|
56
|
+
production database 'test'. Warned you.
|
57
|
+
|
58
|
+
Details can be changed in spec/spec_helper.rb
|
59
|
+
|
60
|
+
== THANKS
|
61
|
+
|
62
|
+
Special Thanks to Florian Hanke (florian at restorm dot com) and Severin Schoepke (severin at restorm dot com).
|
63
|
+
They have played an enormous role in keeping this mean and lean. Thanks also to the rest of the gang - please
|
64
|
+
visit us at labs.restorm.com.
|
65
|
+
|
66
|
+
== CONTACT
|
67
|
+
|
68
|
+
Rubyforge Project:
|
69
|
+
|
70
|
+
http://rubyforge.org/projects/swissrb
|
71
|
+
|
72
|
+
Documentation:
|
73
|
+
|
74
|
+
upcoming...
|
75
|
+
|
76
|
+
Bugs:
|
77
|
+
|
78
|
+
http://rubyforge.org/tracker/?atid=19774&group_id=5130&func=browse
|
79
|
+
|
80
|
+
|
81
|
+
== LICENSE:
|
82
|
+
|
83
|
+
(The MIT License or the Ruby License, choose)
|
84
|
+
|
85
|
+
Copyright (c) 2007 Kaspar Schiess, all rights reserved
|
86
|
+
|
87
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
88
|
+
a copy of this software and associated documentation files (the
|
89
|
+
'Software'), to deal in the Software without restriction, including
|
90
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
91
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
92
|
+
permit persons to whom the Software is furnished to do so, subject to
|
93
|
+
the following conditions:
|
94
|
+
|
95
|
+
The above copyright notice and this permission notice shall be
|
96
|
+
included in all copies or substantial portions of the Software.
|
97
|
+
|
98
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
99
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
100
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
101
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
102
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
103
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
104
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
105
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require './lib/scoped_proxy'
|
4
|
+
|
5
|
+
namespace :hoe do
|
6
|
+
Hoe.new('ScopedProxy', ScopedProxy::VERSION) do |p|
|
7
|
+
p.rubyforge_name = 'swissrb'
|
8
|
+
p.author = 'Kaspar Schiess'
|
9
|
+
p.email = 'eule@space.ch'
|
10
|
+
p.summary = p.paragraphs_of('README.txt', 1..3).join("\n\n")
|
11
|
+
p.description = p.paragraphs_of('README.txt', 4..7).join(' ')
|
12
|
+
p.url = p.paragraphs_of('README.txt', 17).join(' ')
|
13
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'spec/rake/spectask'
|
18
|
+
require 'spec/translator'
|
19
|
+
|
20
|
+
task :default => :spec
|
21
|
+
|
22
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
24
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
data/lib/scoped_proxy.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'metaid'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
# Smart scoping for AR models
|
5
|
+
# Author: Kaspar Schiess, (c) by Neotrivium AG, 2007
|
6
|
+
# Distributed under the terms of the Ruby License
|
7
|
+
|
8
|
+
module ScopedProxy
|
9
|
+
VERSION = '1.0.0'
|
10
|
+
|
11
|
+
# Allows you to create scoped proxies in models.
|
12
|
+
#
|
13
|
+
# Example
|
14
|
+
#
|
15
|
+
# class User < ActiveRecord::Base
|
16
|
+
# scoped_proxy :woman, :find => { :conditions => ['sex=?', 'f'] }
|
17
|
+
#
|
18
|
+
# Allowed options
|
19
|
+
# * :exclusive if set to true, this proxy will not apply if there is another proxy active.
|
20
|
+
#
|
21
|
+
class Proxy
|
22
|
+
cattr_accessor :active_proxy
|
23
|
+
@@active_proxy = false
|
24
|
+
|
25
|
+
def initialize(klass, scope={}, old_scope=nil, options={})
|
26
|
+
@klass, @scope, @old_scope = klass, scope, old_scope
|
27
|
+
@options = options
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(message, *args, &block)
|
31
|
+
exclusive_scope = @options[:exclusive] || false
|
32
|
+
activate_proxy = (! exclusive_scope) || (exclusive_scope && no_other_proxy_active?)
|
33
|
+
|
34
|
+
conditional_scope(@old_scope) do # Install previous scope
|
35
|
+
conditional_scope(@scope, activate_proxy) do # Install this scope
|
36
|
+
with_proxy do # Track active proxies
|
37
|
+
@klass.send(message, *args, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def respond_to_with_delegation?(symbol)
|
44
|
+
self.respond_to_without_delegation?(symbol) || @klass.respond_to?(symbol)
|
45
|
+
end
|
46
|
+
alias_method_chain :respond_to?, :delegation
|
47
|
+
|
48
|
+
# Mark the installation of a proxy. This information can be used to make proxies dependent upon context, as in
|
49
|
+
# the default proxy.
|
50
|
+
#
|
51
|
+
def with_proxy
|
52
|
+
begin
|
53
|
+
old_value = self.class.active_proxy
|
54
|
+
self.class.active_proxy = true
|
55
|
+
yield
|
56
|
+
ensure
|
57
|
+
self.class.active_proxy = old_value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Is there no other proxy than this one active?
|
62
|
+
#
|
63
|
+
def no_other_proxy_active?
|
64
|
+
! self.class.active_proxy
|
65
|
+
end
|
66
|
+
|
67
|
+
# Install given scope if it is not nil and the predicate is true. Then yield.
|
68
|
+
#
|
69
|
+
def conditional_scope(scope, pred=true)
|
70
|
+
if scope && pred
|
71
|
+
klass_with_scope(@klass, scope) do
|
72
|
+
yield
|
73
|
+
end
|
74
|
+
else
|
75
|
+
yield
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Permit access to with_scope from outside the AR::Base class. This is an exception to the rule ;)
|
80
|
+
#
|
81
|
+
def klass_with_scope(klass, scope, &block)
|
82
|
+
klass.send(:with_scope, scope, &block)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.included(base)
|
87
|
+
base.extend(ClassMethods)
|
88
|
+
end
|
89
|
+
|
90
|
+
module ClassMethods
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Add a default proxy to the object. A default proxy is a proxy that is always in effect, unless another proxy is
|
95
|
+
# used.
|
96
|
+
#
|
97
|
+
# Example
|
98
|
+
#
|
99
|
+
# class User
|
100
|
+
# default_proxy :find => { :conditions => { :deleted_at => nil } }
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# The example only returns users that haven't been marked as deleted - unless you use another proxy on the User
|
104
|
+
# object.
|
105
|
+
#
|
106
|
+
def default_proxy(scope=nil)
|
107
|
+
scoped_proxy :default_proxy, scope, :exclusive => true
|
108
|
+
|
109
|
+
[:find, :count].each do |meth|
|
110
|
+
meth_name = "#{meth}_with_default_proxy"
|
111
|
+
meth_without = "#{meth}_without_default_proxy"
|
112
|
+
metaclass.class_eval %Q{
|
113
|
+
def #{meth_name}(*args, &block)
|
114
|
+
default_proxy.#{meth_without}(*args, &block)
|
115
|
+
end
|
116
|
+
alias_method_chain :#{meth}, :default_proxy
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Install a scoped proxy with the given name.
|
122
|
+
#
|
123
|
+
# Example
|
124
|
+
#
|
125
|
+
# class User < ActiveRecord::Base
|
126
|
+
# scoped_proxy :woman, :find => { :conditions => ['sex=?', 'f'] }
|
127
|
+
#
|
128
|
+
def scoped_proxy(name, scope=nil, opts={}, &block)
|
129
|
+
meta_def(name) do |*args|
|
130
|
+
resulting_scope = scope
|
131
|
+
resulting_scope = block.call(*args) if block
|
132
|
+
|
133
|
+
target = self
|
134
|
+
Proxy.new(target, resulting_scope, self.current_scoped_methods, opts)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class ActiveRecord::Base
|
141
|
+
include ScopedProxy
|
142
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
4
|
+
require 'scoped_proxy'
|
5
|
+
|
6
|
+
def silence
|
7
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
8
|
+
yield
|
9
|
+
ensure
|
10
|
+
$VERBOSE = old_verbose
|
11
|
+
end
|
12
|
+
|
13
|
+
# NOTE: Running these tests WILL destroy a database called test (overwriting tables and such). You have been warned.
|
14
|
+
|
15
|
+
describe ScopedProxy, " availability" do
|
16
|
+
it "should be a module" do
|
17
|
+
ScopedProxy.should be_kind_of(Module)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
silence do
|
22
|
+
ActiveRecord::Schema.define do
|
23
|
+
create_table :users, :force => true do |t|
|
24
|
+
t.column :name, :string
|
25
|
+
t.column :role, :string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
class User < ActiveRecord::Base
|
30
|
+
scoped_proxy :johns, :find => {
|
31
|
+
:conditions => ['name like ?', 'john%']
|
32
|
+
}
|
33
|
+
scoped_proxy :janes, :find => {
|
34
|
+
:conditions => ['name like ?', 'jane%']
|
35
|
+
}
|
36
|
+
end
|
37
|
+
john1 = User.create!(:name => 'john1', :role => 'admin')
|
38
|
+
john2 = User.create!(:name => 'john2', :role => 'user')
|
39
|
+
jane1 = User.create!(:name => 'jane1', :role => 'user')
|
40
|
+
|
41
|
+
describe User, " and users that are john" do
|
42
|
+
it "should have johns" do
|
43
|
+
User.should respond_to(:johns)
|
44
|
+
end
|
45
|
+
it "johns should return a proxy" do
|
46
|
+
User.johns.should be_kind_of(ScopedProxy::Proxy)
|
47
|
+
end
|
48
|
+
it "should allow us to find all johns" do
|
49
|
+
johns = User.find(:all, :conditions => 'name like \'john%\'')
|
50
|
+
|
51
|
+
User.johns.find(:all).should eql(johns)
|
52
|
+
end
|
53
|
+
it "should have count and other methods" do
|
54
|
+
User.johns.find(:all)
|
55
|
+
User.johns.count
|
56
|
+
end
|
57
|
+
it "should respond to count and other methods" do
|
58
|
+
User.johns.should respond_to(:count)
|
59
|
+
User.johns.should respond_to(:find)
|
60
|
+
User.johns.should respond_to(:destroy_all)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class User
|
65
|
+
scoped_proxy :role do |role|
|
66
|
+
{
|
67
|
+
:find => { :conditions => ['role = ?', role] }
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
describe User, "extended scoping" do
|
72
|
+
it "should have role proxy" do
|
73
|
+
User.should respond_to(:role)
|
74
|
+
end
|
75
|
+
it "should select roles as a filter" do
|
76
|
+
['admin', 'user'].each do |role|
|
77
|
+
expectation = User.find(:all, :conditions => {:role => role} )
|
78
|
+
User.role(role).find(:all).should eql(expectation)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
it "should allow combining roles into a bigger filter" do
|
82
|
+
# try both orders
|
83
|
+
User.janes.role('user').find(:first).should eql(jane1)
|
84
|
+
User.role('user').janes.find(:first).should eql(jane1)
|
85
|
+
end
|
86
|
+
it "should allow storing proxy and later on using it" do
|
87
|
+
janes = User.janes
|
88
|
+
|
89
|
+
janes.find(:first).should eql(jane1)
|
90
|
+
end
|
91
|
+
it "should capture its environment" do
|
92
|
+
johns = nil
|
93
|
+
User.send(:with_scope, :find => {:conditions => { :role => 'user'} } ) do
|
94
|
+
johns = User.johns
|
95
|
+
end
|
96
|
+
|
97
|
+
johns.find(:all).should eql([john2])
|
98
|
+
end
|
99
|
+
it "should capture a complex scoped environment" do
|
100
|
+
johns = nil
|
101
|
+
User.send(:with_scope, :find => {:conditions => { :role => 'user'} } ) do
|
102
|
+
johns = User.johns.role('admin')
|
103
|
+
end
|
104
|
+
|
105
|
+
johns.find(:all).should be_empty
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
silence do
|
110
|
+
ActiveRecord::Schema.define do
|
111
|
+
create_table :zebras, :force => true do |t|
|
112
|
+
t.column :stripes, :boolean
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
class Zebra < ActiveRecord::Base
|
117
|
+
default_proxy :find => {
|
118
|
+
:conditions => ['stripes = ?', true]
|
119
|
+
}
|
120
|
+
|
121
|
+
# Any further proxying will go back to unproxied default
|
122
|
+
scoped_proxy :bad
|
123
|
+
end
|
124
|
+
|
125
|
+
# All good zebras have stripes
|
126
|
+
10.times do Zebra.create!(:stripes => true) end
|
127
|
+
# Only some don't
|
128
|
+
Zebra.create!(:stripes => false)
|
129
|
+
|
130
|
+
describe Zebra, "default proxies" do
|
131
|
+
it "should not have johns or janes - that's User" do
|
132
|
+
# NOTE to the confused reader: For johns to be a method on User, it can either be a method of User's class (== Class)
|
133
|
+
# or a method of the singleton metaclass of User (== an anonymous class that inherits from Class). Now, we don't want
|
134
|
+
# stuff we define for the user (like eat_at_a_table) to be defined for all Zebras too - this is why we need #meta_def and
|
135
|
+
# not class_def. The two solutions are otherwise identical - this expectation forces the decision.
|
136
|
+
#
|
137
|
+
Zebra.should_not respond_to(:johns)
|
138
|
+
Zebra.should_not respond_to(:janes)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should select only striped zebras by default" do
|
142
|
+
Zebra.count.should == 10
|
143
|
+
|
144
|
+
Zebra.find(:all).each do |zebra|
|
145
|
+
zebra.stripes.should eql(true)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
it "should select all zebras with any other proxy" do
|
149
|
+
Zebra.send(:with_scope, :find => { :conditions => ['id>0'] }) do
|
150
|
+
Zebra.bad.count.should == 11
|
151
|
+
end
|
152
|
+
Zebra.bad.count.should == 11
|
153
|
+
Zebra.bad.bad.count.should == 11
|
154
|
+
|
155
|
+
Zebra.bad.find(:all, :conditions => { :stripes => false }).each do |zebra|
|
156
|
+
zebra.stripes.should == false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
it "should allow accessing the default proxy trough #default_proxy" do
|
160
|
+
default = Zebra.default_proxy
|
161
|
+
|
162
|
+
default.count.should == 10
|
163
|
+
end
|
164
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ScopedProxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ""
|
6
|
+
authors:
|
7
|
+
- Kaspar Schiess
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2007-12-21 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.0
|
23
|
+
version:
|
24
|
+
description: "== SYNOPSIS: Allows storing scopes as names; that way you can address subsets of your model space by meaningful names. require 'scoped_proxy' # Railsers: You might want to call this in environment.rb class User < ActiveRecord::Base scoped_proxy :role do |role| { :find => { :conditions => ['role = ?', role] } } end scoped_proxy :deleted, :find => { :conditions => 'deleted_at is not null' } end admins = User.role('admin') admins.count # => 12 admins.find(:all) # => [ ... ] User.deleted.count # => a number This implementation also brings (NEW, SHINY) default proxies. That means you can have a proxy in effect when no other proxy is in effect. class User < ActiveRecord::Base default_proxy :find => { :conditions => 'deleted_at is null' } end User.find(:all) # only finds users that aren't deleted"
|
25
|
+
email: eule@space.ch
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- History.txt
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
files:
|
35
|
+
- History.txt
|
36
|
+
- Manifest.txt
|
37
|
+
- README.txt
|
38
|
+
- Rakefile
|
39
|
+
- lib/scoped_proxy.rb
|
40
|
+
- spec/scoped_proxy_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://rubyforge.org/projects/swissrb
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README.txt
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: swissrb
|
65
|
+
rubygems_version: 0.9.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: == SUMMARY Finally, long awaited, scoped proxies as a release. Which you say. Admitted, there are about 15 plugins that are called scoped_proxy, but only one comes with a full suite of tests that is full 40 lines longer than the actual code. That is the scoped proxy you are looking at. It is y2k compliant and works as a gem. Magnificent, isn't it? This gem is all about simplicity; you won't find a whole toolbox here, just another valued screwdriver. But we happen to encounter a lot of screws - hopefully you do too - and find this very useful. If you want to skip all this summary that is really longer than all the other texts in this release, have a look at the synopsis below.
|
69
|
+
test_files: []
|
70
|
+
|