active_access 0.1.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/.rspec +1 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +67 -0
- data/Rakefile +44 -0
- data/lib/active_access.rb +9 -0
- data/lib/active_access/attribute_conventions.rb +40 -0
- data/lib/active_access/attribute_methods.rb +78 -0
- data/spec/active_access_spec.rb +145 -0
- data/spec/spec_helper.rb +14 -0
- metadata +137 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Riley Lynch, Teleological Software, LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
= active_access
|
2
|
+
|
3
|
+
The ActiveAccess mixin makes it easy to limit access to ActiveModel
|
4
|
+
and ActiveRecord attributes by declaring generated attribute accessor
|
5
|
+
methods private.
|
6
|
+
|
7
|
+
Mixing the <tt>ActiveAcess::AttributeMethods</tt> into a class that mixes
|
8
|
+
in ActiveModel::AttributeMethods or is derived from ActiveRecord::Base
|
9
|
+
adds the <tt>attr_private</tt> and <tt>attr_private_writer</tt> macros.
|
10
|
+
|
11
|
+
These macros change the behavior of +define_attribute_methods+ to declare
|
12
|
+
generated attribute accessors private: +attr_private+ declares all
|
13
|
+
accessors for an attribute private; +attr_private_writer+ declares only
|
14
|
+
writer methods private.
|
15
|
+
|
16
|
+
ActiveAccess recognizes the following attribute reader method name
|
17
|
+
patterns:
|
18
|
+
|
19
|
+
#name
|
20
|
+
#name?
|
21
|
+
#name_before_type_cast
|
22
|
+
#name_changed?
|
23
|
+
#name_change
|
24
|
+
#name_was
|
25
|
+
#_name
|
26
|
+
|
27
|
+
ActiveAccess recognizes the following attribute writer method name
|
28
|
+
patterns:
|
29
|
+
|
30
|
+
#name=
|
31
|
+
#name_will_change
|
32
|
+
#reset_name!
|
33
|
+
|
34
|
+
== Example
|
35
|
+
|
36
|
+
class Widget < ActiveRecord::Base
|
37
|
+
|
38
|
+
include ActiveAccess::AttributeMethods
|
39
|
+
|
40
|
+
attr_private_writer :read_me
|
41
|
+
|
42
|
+
attr_private :secret
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
Widget.new.respond_to? :read_me # => true
|
47
|
+
Widget.new.read_me = "new value" # raises NoMethodError
|
48
|
+
|
49
|
+
Widget.new.respond_to? :secret # => false
|
50
|
+
Widget.new.secret = "new value" # raises NoMethodError
|
51
|
+
|
52
|
+
== Limitations
|
53
|
+
|
54
|
+
ActiveAccess only restricts access to named attribute accessors. Unnamed
|
55
|
+
accessors such as ActiveRecord +read_attribute+ and +write_attribute+ as
|
56
|
+
well as hash-style access are not restricted. Attribute aliases are also
|
57
|
+
unrestricted.
|
58
|
+
|
59
|
+
ActiveRecord does not allow attributes with private writers to be
|
60
|
+
initialized (i.e. passed as parameters to +new+) or mass-assigned
|
61
|
+
(passed as parameters to +assign_attributes+ or +attributes=+).
|
62
|
+
|
63
|
+
== Copyright
|
64
|
+
|
65
|
+
Copyright (c) 2012 Riley Lynch, Teleological Software, LLC.
|
66
|
+
See LICENSE.txt for further details.
|
67
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
gem.name = "active_access"
|
17
|
+
gem.homepage = "http://github.com/teleological/active_access"
|
18
|
+
gem.license = "MIT"
|
19
|
+
gem.summary =
|
20
|
+
%Q{Access control for ActiveModel/ActiveRecord attributes}
|
21
|
+
gem.description =
|
22
|
+
%Q{Access control for ActiveModel/ActiveRecord attributes}
|
23
|
+
gem.authors = ["Riley Lynch"]
|
24
|
+
end
|
25
|
+
Jeweler::RubygemsDotOrgTasks.new
|
26
|
+
|
27
|
+
require 'rspec/core'
|
28
|
+
require 'rspec/core/rake_task'
|
29
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
30
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
task :default => :spec
|
34
|
+
|
35
|
+
require 'rdoc/task'
|
36
|
+
Rake::RDocTask.new do |rdoc|
|
37
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
38
|
+
rdoc.main = "README.rdoc"
|
39
|
+
rdoc.rdoc_dir = 'rdoc'
|
40
|
+
rdoc.rdoc_files.include('README*')
|
41
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
42
|
+
rdoc.title = "active_access #{version}"
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
require 'active_model'
|
3
|
+
|
4
|
+
module ActiveAccess
|
5
|
+
class AttributeConventions
|
6
|
+
|
7
|
+
MethodMatcher = ActiveModel::AttributeMethods::ClassMethods::
|
8
|
+
AttributeMethodMatcher
|
9
|
+
|
10
|
+
READ_MATCHERS = [
|
11
|
+
MethodMatcher.new, # "plain" reader
|
12
|
+
MethodMatcher.new(suffix: '_changed?'),
|
13
|
+
MethodMatcher.new(suffix: '_change'),
|
14
|
+
MethodMatcher.new(suffix: '_was'),
|
15
|
+
MethodMatcher.new(suffix: '_before_type_cast'),
|
16
|
+
MethodMatcher.new(prefix: '_'),
|
17
|
+
MethodMatcher.new(prefix: '?')
|
18
|
+
]
|
19
|
+
|
20
|
+
WRITE_MATCHERS = [
|
21
|
+
MethodMatcher.new(prefix: 'reset_', suffix: '!'),
|
22
|
+
MethodMatcher.new(suffix: '_will_change'),
|
23
|
+
MethodMatcher.new(suffix: '=')
|
24
|
+
]
|
25
|
+
|
26
|
+
class << self
|
27
|
+
|
28
|
+
def reader_names(attr)
|
29
|
+
READ_MATCHERS.map { |matcher| matcher.method_name(attr) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def writer_names(attr)
|
33
|
+
WRITE_MATCHERS.map { |matcher| matcher.method_name(attr) }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
module ActiveAccess
|
5
|
+
module AttributeMethods
|
6
|
+
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :_attribute_access, :instance_writer => false
|
11
|
+
self._attribute_access = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def attr_private(*attrs)
|
17
|
+
update_attribute_method_access(:private, attrs)
|
18
|
+
end
|
19
|
+
|
20
|
+
def attr_private_writer(*attrs)
|
21
|
+
update_attribute_method_access(:readonly, attrs)
|
22
|
+
end
|
23
|
+
|
24
|
+
def define_attribute_methods(attrs=nil)
|
25
|
+
if defined?(ActiveRecord) && (self < ActiveRecord::AttributeMethods)
|
26
|
+
super() # takes no arguments
|
27
|
+
reset_attribute_method_access
|
28
|
+
else
|
29
|
+
super # takes a list of attribute names as arguments
|
30
|
+
reset_attribute_method_access(attrs)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def update_attribute_method_access(level, attrs)
|
37
|
+
self._attribute_access = self._attribute_access.dup
|
38
|
+
attrs.each do |attr|
|
39
|
+
self._attribute_access[attr.to_sym] = level
|
40
|
+
end
|
41
|
+
reset_attribute_method_access(attrs)
|
42
|
+
end
|
43
|
+
|
44
|
+
def reset_attribute_method_access(attrs=nil)
|
45
|
+
|
46
|
+
if attrs
|
47
|
+
attr_syms = attrs.map(&:to_sym)
|
48
|
+
attr_accesses = _attribute_access.slice(*attr_syms)
|
49
|
+
else
|
50
|
+
attr_accesses = _attribute_access
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_accesses.each do |attr, access|
|
54
|
+
if [:private, :readonly].include?(access)
|
55
|
+
privatize_attribute_writers(attr)
|
56
|
+
end
|
57
|
+
privatize_attribute_readers(attr) if access == :private
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def privatize_attribute_writers(attr)
|
63
|
+
AttributeConventions.writer_names(attr).each do |name|
|
64
|
+
private name if method_defined?(name)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def privatize_attribute_readers(attr)
|
69
|
+
AttributeConventions.reader_names(attr).each do |name|
|
70
|
+
private name if method_defined?(name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
describe "ActiveAccess::AttributeMethods" do
|
6
|
+
|
7
|
+
context "given an ActiveModel class" do
|
8
|
+
|
9
|
+
let(:abstract_base_class) do
|
10
|
+
Class.new(Struct.new(:foo, :bar, :baz)).tap do |klass|
|
11
|
+
klass.class_eval do
|
12
|
+
|
13
|
+
include ActiveModel::AttributeMethods
|
14
|
+
include ActiveAccess::AttributeMethods
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
members.each_with_object({}) { |m, h| h[m.to_s] = self[m] }
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :attribute, :[]
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:model_instance) { model_class.new("fooh", "bhar", "bazh") }
|
27
|
+
|
28
|
+
let(:private_attribute) { :bar }
|
29
|
+
let(:private_attribute_value) { "bhar" }
|
30
|
+
|
31
|
+
let(:private_reader) { :"#{private_attribute}" }
|
32
|
+
let(:private_writer) { :"#{private_attribute}=" }
|
33
|
+
|
34
|
+
shared_examples_for "any ActiveModel class with private attributes" do
|
35
|
+
|
36
|
+
it "prevents public reads with named reader on private attributes" do
|
37
|
+
lambda { model_instance.public_send(private_reader) }.
|
38
|
+
should raise_error(NoMethodError, /private/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "prevents public writes with named writer on private attributes" do
|
42
|
+
lambda { model_instance.public_send(private_writer,"changed") }.
|
43
|
+
should raise_error(NoMethodError, /private/)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "allows private reads with named reader on private attributes" do
|
47
|
+
model_instance.send(private_reader).
|
48
|
+
should == private_attribute_value
|
49
|
+
end
|
50
|
+
|
51
|
+
it "allows private writes with named writer on private attributes" do
|
52
|
+
model_instance.send(private_writer, "changed")
|
53
|
+
model_instance.send(private_reader).should == "changed"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "allows read access to private attributes via unnamed reader" do
|
57
|
+
model_instance[private_attribute].should == private_attribute_value
|
58
|
+
end
|
59
|
+
|
60
|
+
it "allows read access to private attributes via unnamed reader" do
|
61
|
+
model_instance[private_attribute] = "changed"
|
62
|
+
model_instance[private_attribute].should == "changed"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
shared_examples_for "any ActiveModel class" do
|
68
|
+
|
69
|
+
it_should_behave_like "any ActiveModel class with private attributes"
|
70
|
+
|
71
|
+
it "allows public reads on public (default) attributes" do
|
72
|
+
model_instance.foo.should == "fooh"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "allows public writes to public (default) attributes" do
|
76
|
+
model_instance.foo = "fhoo"
|
77
|
+
model_instance.foo.should == "fhoo"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when private attributes are declared before methods" do
|
83
|
+
|
84
|
+
let(:model_class) do
|
85
|
+
Class.new(abstract_base_class).tap do |klass|
|
86
|
+
klass.class_eval do
|
87
|
+
attr_private :bar
|
88
|
+
define_attribute_methods([:foo, :bar, :baz])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it_should_behave_like "any ActiveModel class"
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when attribute methods are declared before privacy" do
|
98
|
+
|
99
|
+
let(:model_class) do
|
100
|
+
Class.new(abstract_base_class).tap do |klass|
|
101
|
+
klass.class_eval do
|
102
|
+
define_attribute_methods([:foo, :bar, :baz])
|
103
|
+
attr_private :bar
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it_should_behave_like "any ActiveModel class"
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when attributes are inherited " do
|
113
|
+
|
114
|
+
let(:base_class) do
|
115
|
+
Class.new(abstract_base_class).tap do |klass|
|
116
|
+
klass.class_eval do
|
117
|
+
define_attribute_methods([:foo, :bar])
|
118
|
+
attr_private :bar
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
let(:model_class) do
|
124
|
+
Class.new(base_class).tap do |klass|
|
125
|
+
klass.class_eval do
|
126
|
+
define_attribute_methods([:baz])
|
127
|
+
attr_private :baz
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "with inherited private attributes" do
|
133
|
+
it_should_behave_like "any ActiveModel class"
|
134
|
+
end
|
135
|
+
|
136
|
+
context "with derived private attributes" do
|
137
|
+
let(:private_attribute) { :baz }
|
138
|
+
let(:private_attribute_value) { "bazh" }
|
139
|
+
it_should_behave_like "any ActiveModel class"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
require 'active_access'
|
7
|
+
|
8
|
+
# Requires supporting files with custom matchers and macros, etc,
|
9
|
+
# in ./support/ and its subdirectories.
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_access
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Riley Lynch
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemodel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rdoc
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: jeweler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Access control for ActiveModel/ActiveRecord attributes
|
95
|
+
email:
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files:
|
99
|
+
- LICENSE.txt
|
100
|
+
- README.rdoc
|
101
|
+
files:
|
102
|
+
- .rspec
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.rdoc
|
106
|
+
- Rakefile
|
107
|
+
- lib/active_access.rb
|
108
|
+
- lib/active_access/attribute_conventions.rb
|
109
|
+
- lib/active_access/attribute_methods.rb
|
110
|
+
- spec/active_access_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
homepage: http://github.com/teleological/active_access
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 1.8.24
|
134
|
+
signing_key:
|
135
|
+
specification_version: 3
|
136
|
+
summary: Access control for ActiveModel/ActiveRecord attributes
|
137
|
+
test_files: []
|