aclatraz 0.1.2 → 0.1.3
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/CHANGELOG.rdoc +7 -0
- data/README.rdoc +2 -2
- data/Rakefile +33 -18
- data/TODO.rdoc +2 -0
- data/VERSION +1 -1
- data/aclatraz.gemspec +17 -14
- data/lib/aclatraz/helpers.rb +23 -2
- data/lib/aclatraz/store.rb +1 -0
- data/lib/aclatraz/store/cassandra.rb +63 -0
- data/lib/aclatraz/store/redis.rb +23 -50
- data/lib/aclatraz/store/riak.rb +21 -33
- data/spec/aclatraz/guard_spec.rb +1 -1
- data/spec/aclatraz/helpers_spec.rb +17 -0
- data/spec/aclatraz/stores_spec.rb +16 -4
- data/spec/aclatraz/suspect_spec.rb +1 -1
- data/spec/aclatraz_spec.rb +1 -1
- data/spec/alcatraz_bm.rb +4 -10
- data/spec/spec_helper.rb +2 -3
- metadata +40 -26
- data/spec/spec.opts +0 -2
    
        data/CHANGELOG.rdoc
    CHANGED
    
    
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            = ACLatraz
         | 
| 2 2 |  | 
| 3 | 
            -
            Extremaly fast and  | 
| 4 | 
            -
             | 
| 3 | 
            +
            Extremaly fast, flexible and intuitive access control mechanism, powered by 
         | 
| 4 | 
            +
            fast key value stores like Redis.
         | 
| 5 5 |  | 
| 6 6 | 
             
            == Installation
         | 
| 7 7 |  | 
    
        data/Rakefile
    CHANGED
    
    | @@ -5,35 +5,36 @@ begin | |
| 5 5 | 
             
              require 'jeweler'
         | 
| 6 6 | 
             
              Jeweler::Tasks.new do |gem|
         | 
| 7 7 | 
             
                gem.name = "aclatraz"
         | 
| 8 | 
            -
                gem.summary = %Q{Flexible access control that doesn't sucks!}
         | 
| 9 | 
            -
                gem.description = <<-DESCR
         | 
| 10 | 
            -
                  Extremaly fast and flexible access control mechanism inspired by *nix ACLs, 
         | 
| 11 | 
            -
                  powered by fast key value stores like Redis or TokyoCabinet.
         | 
| 12 | 
            -
                DESCR
         | 
| 13 8 | 
             
                gem.email = "kriss.kowalik@gmail.com"
         | 
| 14 9 | 
             
                gem.homepage = "http://github.com/nu7hatch/aclatraz"
         | 
| 15 10 | 
             
                gem.authors = ["Kriss 'nu7hatch' Kowalik"]
         | 
| 16 | 
            -
                gem. | 
| 17 | 
            -
                gem. | 
| 11 | 
            +
                gem.summary = %Q{Flexible access control that doesn't sucks!}
         | 
| 12 | 
            +
                gem.description = <<-DESCR
         | 
| 13 | 
            +
                  Extremaly fast, flexible and intuitive access control mechanism, 
         | 
| 14 | 
            +
                  powered by fast key value stores like Redis.
         | 
| 15 | 
            +
                DESCR
         | 
| 16 | 
            +
                gem.add_dependency "dictionary", "~> 1.0"
         | 
| 17 | 
            +
                gem.add_development_dependency "rspec", "~> 2.0"
         | 
| 18 | 
            +
                gem.add_development_dependency "mocha", "~> 0.9"
         | 
| 18 19 | 
             
                gem.add_development_dependency "redis", "~> 2.0"
         | 
| 19 20 | 
             
                gem.add_development_dependency "riak-client", "~> 0.8"
         | 
| 20 | 
            -
                gem. | 
| 21 | 
            +
                gem.add_development_dependency "cassandra", "~> 0.8"
         | 
| 21 22 | 
             
              end
         | 
| 22 23 | 
             
              Jeweler::GemcutterTasks.new
         | 
| 23 24 | 
             
            rescue LoadError
         | 
| 24 25 | 
             
              puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
         | 
| 25 26 | 
             
            end
         | 
| 26 27 |  | 
| 27 | 
            -
            require ' | 
| 28 | 
            -
             | 
| 29 | 
            -
               | 
| 30 | 
            -
               | 
| 28 | 
            +
            require 'rspec/core/rake_task'
         | 
| 29 | 
            +
            RSpec::Core::RakeTask.new(:spec) do |t|
         | 
| 30 | 
            +
              t.pattern = 'spec/**/*_spec.rb'
         | 
| 31 | 
            +
              t.rspec_opts = %q[--colour --backtrace]
         | 
| 31 32 | 
             
            end
         | 
| 32 33 |  | 
| 33 | 
            -
             | 
| 34 | 
            -
               | 
| 35 | 
            -
               | 
| 36 | 
            -
               | 
| 34 | 
            +
            RSpec::Core::RakeTask.new(:rcov) do |t|
         | 
| 35 | 
            +
              t.rcov = true
         | 
| 36 | 
            +
              t.rspec_opts = %q[--colour --backtrace]
         | 
| 37 | 
            +
              t.rcov_opts = %q[--exclude "spec" --text-report]
         | 
| 37 38 | 
             
            end
         | 
| 38 39 |  | 
| 39 40 | 
             
            task :spec => :check_dependencies
         | 
| @@ -48,7 +49,21 @@ Rake::RDocTask.new do |rdoc| | |
| 48 49 | 
             
              rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 49 50 | 
             
            end
         | 
| 50 51 |  | 
| 51 | 
            -
             | 
| 52 | 
            +
            namespace :benchmark do 
         | 
| 53 | 
            +
              $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
         | 
| 52 54 | 
             
              require 'benchmark'
         | 
| 53 | 
            -
              require  | 
| 55 | 
            +
              require "aclatraz"
         | 
| 56 | 
            +
              
         | 
| 57 | 
            +
              task :redis do 
         | 
| 58 | 
            +
                Aclatraz.init(:redis)
         | 
| 59 | 
            +
                require File.dirname(__FILE__)+"/spec/alcatraz_bm"
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
              task :cassandra do 
         | 
| 62 | 
            +
                Aclatraz.init(:cassandra, "Super1", "Keyspace1")
         | 
| 63 | 
            +
                require File.dirname(__FILE__)+"/spec/alcatraz_bm"
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
              task :riak do
         | 
| 66 | 
            +
                Aclatraz.init(:riak, "roles")
         | 
| 67 | 
            +
                require File.dirname(__FILE__)+"/spec/alcatraz_bm"
         | 
| 68 | 
            +
              end
         | 
| 54 69 | 
             
            end
         | 
    
        data/TODO.rdoc
    CHANGED
    
    
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.1. | 
| 1 | 
            +
            0.1.3
         | 
    
        data/aclatraz.gemspec
    CHANGED
    
    | @@ -5,13 +5,13 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{aclatraz}
         | 
| 8 | 
            -
              s.version = "0.1. | 
| 8 | 
            +
              s.version = "0.1.3"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["Kriss 'nu7hatch' Kowalik"]
         | 
| 12 | 
            -
              s.date = %q{2010- | 
| 13 | 
            -
              s.description = %q{      Extremaly fast and  | 
| 14 | 
            -
                  powered by fast key value stores like Redis | 
| 12 | 
            +
              s.date = %q{2010-10-16}
         | 
| 13 | 
            +
              s.description = %q{      Extremaly fast, flexible and intuitive access control mechanism, 
         | 
| 14 | 
            +
                  powered by fast key value stores like Redis.
         | 
| 15 15 | 
             
            }
         | 
| 16 16 | 
             
              s.email = %q{kriss.kowalik@gmail.com}
         | 
| 17 17 | 
             
              s.extra_rdoc_files = [
         | 
| @@ -34,6 +34,7 @@ Gem::Specification.new do |s| | |
| 34 34 | 
             
                 "lib/aclatraz/guard.rb",
         | 
| 35 35 | 
             
                 "lib/aclatraz/helpers.rb",
         | 
| 36 36 | 
             
                 "lib/aclatraz/store.rb",
         | 
| 37 | 
            +
                 "lib/aclatraz/store/cassandra.rb",
         | 
| 37 38 | 
             
                 "lib/aclatraz/store/redis.rb",
         | 
| 38 39 | 
             
                 "lib/aclatraz/store/riak.rb",
         | 
| 39 40 | 
             
                 "lib/aclatraz/suspect.rb",
         | 
| @@ -44,7 +45,6 @@ Gem::Specification.new do |s| | |
| 44 45 | 
             
                 "spec/aclatraz/suspect_spec.rb",
         | 
| 45 46 | 
             
                 "spec/aclatraz_spec.rb",
         | 
| 46 47 | 
             
                 "spec/alcatraz_bm.rb",
         | 
| 47 | 
            -
                 "spec/spec.opts",
         | 
| 48 48 | 
             
                 "spec/spec_helper.rb"
         | 
| 49 49 | 
             
              ]
         | 
| 50 50 | 
             
              s.homepage = %q{http://github.com/nu7hatch/aclatraz}
         | 
| @@ -69,24 +69,27 @@ Gem::Specification.new do |s| | |
| 69 69 | 
             
                s.specification_version = 3
         | 
| 70 70 |  | 
| 71 71 | 
             
                if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
         | 
| 72 | 
            -
                  s. | 
| 73 | 
            -
                  s.add_development_dependency(%q< | 
| 72 | 
            +
                  s.add_runtime_dependency(%q<dictionary>, ["~> 1.0"])
         | 
| 73 | 
            +
                  s.add_development_dependency(%q<rspec>, ["~> 2.0"])
         | 
| 74 | 
            +
                  s.add_development_dependency(%q<mocha>, ["~> 0.9"])
         | 
| 74 75 | 
             
                  s.add_development_dependency(%q<redis>, ["~> 2.0"])
         | 
| 75 76 | 
             
                  s.add_development_dependency(%q<riak-client>, ["~> 0.8"])
         | 
| 76 | 
            -
                  s. | 
| 77 | 
            +
                  s.add_development_dependency(%q<cassandra>, ["~> 0.8"])
         | 
| 77 78 | 
             
                else
         | 
| 78 | 
            -
                  s.add_dependency(%q< | 
| 79 | 
            -
                  s.add_dependency(%q< | 
| 79 | 
            +
                  s.add_dependency(%q<dictionary>, ["~> 1.0"])
         | 
| 80 | 
            +
                  s.add_dependency(%q<rspec>, ["~> 2.0"])
         | 
| 81 | 
            +
                  s.add_dependency(%q<mocha>, ["~> 0.9"])
         | 
| 80 82 | 
             
                  s.add_dependency(%q<redis>, ["~> 2.0"])
         | 
| 81 83 | 
             
                  s.add_dependency(%q<riak-client>, ["~> 0.8"])
         | 
| 82 | 
            -
                  s.add_dependency(%q< | 
| 84 | 
            +
                  s.add_dependency(%q<cassandra>, ["~> 0.8"])
         | 
| 83 85 | 
             
                end
         | 
| 84 86 | 
             
              else
         | 
| 85 | 
            -
                s.add_dependency(%q< | 
| 86 | 
            -
                s.add_dependency(%q< | 
| 87 | 
            +
                s.add_dependency(%q<dictionary>, ["~> 1.0"])
         | 
| 88 | 
            +
                s.add_dependency(%q<rspec>, ["~> 2.0"])
         | 
| 89 | 
            +
                s.add_dependency(%q<mocha>, ["~> 0.9"])
         | 
| 87 90 | 
             
                s.add_dependency(%q<redis>, ["~> 2.0"])
         | 
| 88 91 | 
             
                s.add_dependency(%q<riak-client>, ["~> 0.8"])
         | 
| 89 | 
            -
                s.add_dependency(%q< | 
| 92 | 
            +
                s.add_dependency(%q<cassandra>, ["~> 0.8"])
         | 
| 90 93 | 
             
              end
         | 
| 91 94 | 
             
            end
         | 
| 92 95 |  | 
    
        data/lib/aclatraz/helpers.rb
    CHANGED
    
    | @@ -9,8 +9,29 @@ module Aclatraz | |
| 9 9 |  | 
| 10 10 | 
             
                # If given object is kind of string or integer then returns it, otherwise
         | 
| 11 11 | 
             
                # it tries to return its ID.
         | 
| 12 | 
            -
                def  | 
| 13 | 
            -
                   | 
| 12 | 
            +
                def suspect_id(suspect)
         | 
| 13 | 
            +
                  suspect.is_a?(String) || suspect.is_a?(Integer) ? suspect.to_s : suspect.id.to_s
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                # Unpack given permission data.
         | 
| 17 | 
            +
                def unpack(data)
         | 
| 18 | 
            +
                  data.to_s.split("/")
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                # Pack given permission data.
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                #   pack(foo)               # => "foo"
         | 
| 24 | 
            +
                #   pack(foo, "FooClass")   # => "foo/FooClass"
         | 
| 25 | 
            +
                #   pack(foo, FooClass.new) # => "foo/FooClass/{foo_object_ID}"
         | 
| 26 | 
            +
                def pack(role, object=nil)
         | 
| 27 | 
            +
                  case object
         | 
| 28 | 
            +
                  when nil
         | 
| 29 | 
            +
                    [role]
         | 
| 30 | 
            +
                  when Class 
         | 
| 31 | 
            +
                    [role, object.name]
         | 
| 32 | 
            +
                  else 
         | 
| 33 | 
            +
                    [role, object.class.name, object.id]
         | 
| 34 | 
            +
                  end.join("/")
         | 
| 14 35 | 
             
                end
         | 
| 15 36 | 
             
              end # Helpers
         | 
| 16 37 | 
             
            end # Aclatraz
         | 
    
        data/lib/aclatraz/store.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ module Aclatraz | |
| 2 2 | 
             
              module Store
         | 
| 3 3 | 
             
                autoload :Redis,        'aclatraz/store/redis'
         | 
| 4 4 | 
             
                autoload :Riak,         'aclatraz/store/riak'
         | 
| 5 | 
            +
                autoload :Cassandra,    'aclatraz/store/cassandra'
         | 
| 5 6 | 
             
                #autoload :Memcached,    'aclatraz/store/memcached'
         | 
| 6 7 | 
             
                #autoload :TokyoCabinet, 'aclatraz/store/tokyocabinet'
         | 
| 7 8 | 
             
              end # Store
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            module Aclatraz
         | 
| 2 | 
            +
              module Store
         | 
| 3 | 
            +
                # List of global roles are stored in `roles => all` key. Each suspect has its 
         | 
| 4 | 
            +
                # own key, which contains list of assigned roles. Roles are stored in
         | 
| 5 | 
            +
                # following format:
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                #   roles => suspect.{:suspect_id} =>
         | 
| 8 | 
            +
                #     "role_name" => ""
         | 
| 9 | 
            +
                #     "role_name/ClassName" => ""
         | 
| 10 | 
            +
                #     "role_name/ObjectClass/object_id" => ""
         | 
| 11 | 
            +
                class Cassandra
         | 
| 12 | 
            +
                  include Aclatraz::Helpers
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  ROLES_KEY         = "roles"
         | 
| 15 | 
            +
                  ALL_ROLES_KEY     = "all"
         | 
| 16 | 
            +
                  SUSPECT_ROLES_KEY = "suspect.%s"
         | 
| 17 | 
            +
                  
         | 
| 18 | 
            +
                  def initialize(*args)
         | 
| 19 | 
            +
                    require 'cassandra' rescue raise LoadError, \
         | 
| 20 | 
            +
                      "You must install the `casssandra` gem to use Cassandra store"
         | 
| 21 | 
            +
                    
         | 
| 22 | 
            +
                    @family  = args.shift
         | 
| 23 | 
            +
                    @backend = if args.first.respond_to?(:keyspace)
         | 
| 24 | 
            +
                      args.first
         | 
| 25 | 
            +
                    else
         | 
| 26 | 
            +
                      ::Cassandra.new(*args)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  
         | 
| 30 | 
            +
                  def set(role, suspect, object=nil)
         | 
| 31 | 
            +
                    data = {}
         | 
| 32 | 
            +
                    data[ALL_ROLES_KEY] = [role.to_s] unless object
         | 
| 33 | 
            +
                    data[SUSPECT_ROLES_KEY % suspect_id(suspect)] = [pack(role.to_s, object)]
         | 
| 34 | 
            +
                    @backend.insert(@family, ROLES_KEY, data)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                  def roles(suspect=nil)
         | 
| 38 | 
            +
                    if suspect
         | 
| 39 | 
            +
                      data = @backend.get(@family, ROLES_KEY, SUSPECT_ROLES_KEY % suspect_id(suspect))
         | 
| 40 | 
            +
                      data ? data.keys.map {|role| unpack(role) }.flatten.compact.uniq : []
         | 
| 41 | 
            +
                    else
         | 
| 42 | 
            +
                      data = @backend.get(@family, ROLES_KEY, ALL_ROLES_KEY)
         | 
| 43 | 
            +
                      data ? data.keys.flatten : []
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  
         | 
| 47 | 
            +
                  def check(role, suspect, object=nil)
         | 
| 48 | 
            +
                    @backend.exists?(@family, ROLES_KEY, SUSPECT_ROLES_KEY % suspect_id(suspect), \
         | 
| 49 | 
            +
                      pack(role.to_s, object)) or \
         | 
| 50 | 
            +
                      object && !object.is_a?(Class) ? check(role, suspect, object.class) : false
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                  
         | 
| 53 | 
            +
                  def delete(role, suspect, object=nil)
         | 
| 54 | 
            +
                    @backend.remove(@family, ROLES_KEY, SUSPECT_ROLES_KEY % suspect_id(suspect), \
         | 
| 55 | 
            +
                      pack(role.to_s, object))
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                  
         | 
| 58 | 
            +
                  def clear
         | 
| 59 | 
            +
                    @backend.remove(@family, ROLES_KEY)
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end # Redis
         | 
| 62 | 
            +
              end # Store
         | 
| 63 | 
            +
            end # Aclatraz
         | 
    
        data/lib/aclatraz/store/redis.rb
    CHANGED
    
    | @@ -1,88 +1,61 @@ | |
| 1 | 
            -
            begin
         | 
| 2 | 
            -
              require 'redis'
         | 
| 3 | 
            -
              require 'redis/distributed'
         | 
| 4 | 
            -
            rescue LoadError
         | 
| 5 | 
            -
              raise "You must install the redis gem to use the Redis store"
         | 
| 6 | 
            -
            end
         | 
| 7 | 
            -
             | 
| 8 1 | 
             
            module Aclatraz
         | 
| 9 2 | 
             
              module Store
         | 
| 10 | 
            -
                # List of global roles are stored in ROLES set. Each  | 
| 3 | 
            +
                # List of global roles are stored in ROLES set. Each suspect has its 
         | 
| 11 4 | 
             
                # own key, which contains list of assigned roles. Roles are stored in
         | 
| 12 5 | 
             
                # following format:
         | 
| 13 6 | 
             
                #
         | 
| 14 | 
            -
                #    | 
| 7 | 
            +
                #   suspect.{:suspect_id}.roles:
         | 
| 15 8 | 
             
                #     "role_name"
         | 
| 16 9 | 
             
                #     "role_name/ClassName"
         | 
| 17 10 | 
             
                #     "role_name/ObjectClass/object_id"
         | 
| 18 11 | 
             
                class Redis
         | 
| 19 12 | 
             
                  include Aclatraz::Helpers
         | 
| 20 13 |  | 
| 21 | 
            -
                   | 
| 22 | 
            -
                   | 
| 14 | 
            +
                  ROLES_KEY         = "roles"
         | 
| 15 | 
            +
                  SUSPECT_ROLES_KEY = "suspect.%s.roles"
         | 
| 23 16 |  | 
| 24 | 
            -
                  def initialize(*args) | 
| 25 | 
            -
                     | 
| 26 | 
            -
                       | 
| 17 | 
            +
                  def initialize(*args)
         | 
| 18 | 
            +
                    require 'redis' rescue raise LoadError, \
         | 
| 19 | 
            +
                      "You must install the `redis` gem to use Redis store"
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                    @backend = if args.first.respond_to?(:sadd)
         | 
| 22 | 
            +
                      args.first
         | 
| 27 23 | 
             
                    else
         | 
| 28 | 
            -
                       | 
| 24 | 
            +
                      ::Redis.new(*args)
         | 
| 29 25 | 
             
                    end
         | 
| 30 26 | 
             
                  end
         | 
| 31 27 |  | 
| 32 | 
            -
                  def set(role,  | 
| 28 | 
            +
                  def set(role, suspect, object=nil)
         | 
| 33 29 | 
             
                    @backend.multi do
         | 
| 34 | 
            -
                      @backend.sadd( | 
| 35 | 
            -
                      @backend.sadd( | 
| 30 | 
            +
                      @backend.sadd(ROLES_KEY, role.to_s) unless object
         | 
| 31 | 
            +
                      @backend.sadd(SUSPECT_ROLES_KEY % suspect_id(suspect), pack(role.to_s, object))
         | 
| 36 32 | 
             
                    end
         | 
| 37 33 | 
             
                  end
         | 
| 38 34 |  | 
| 39 | 
            -
                  def roles( | 
| 40 | 
            -
                    if  | 
| 41 | 
            -
                      @backend.smembers( | 
| 35 | 
            +
                  def roles(suspect=nil)
         | 
| 36 | 
            +
                    if suspect
         | 
| 37 | 
            +
                      @backend.smembers(SUSPECT_ROLES_KEY % suspect_id(suspect)).map {|role|
         | 
| 42 38 | 
             
                        role = unpack(role)
         | 
| 43 39 | 
             
                        role[0] if role.size == 1
         | 
| 44 40 | 
             
                      }.compact.uniq
         | 
| 45 41 | 
             
                    else
         | 
| 46 | 
            -
                      @backend.smembers( | 
| 42 | 
            +
                      @backend.smembers(ROLES_KEY)
         | 
| 47 43 | 
             
                    end
         | 
| 48 44 | 
             
                  end
         | 
| 49 45 |  | 
| 50 | 
            -
                  def check(role,  | 
| 51 | 
            -
                    @backend.sismember( | 
| 52 | 
            -
                      object && !object.is_a?(Class) ? check(role,  | 
| 46 | 
            +
                  def check(role, suspect, object=nil)
         | 
| 47 | 
            +
                    @backend.sismember(SUSPECT_ROLES_KEY % suspect_id(suspect), pack(role.to_s, object)) or begin
         | 
| 48 | 
            +
                      object && !object.is_a?(Class) ? check(role, suspect, object.class) : false
         | 
| 53 49 | 
             
                    end
         | 
| 54 50 | 
             
                  end
         | 
| 55 51 |  | 
| 56 | 
            -
                  def delete(role,  | 
| 57 | 
            -
                    @backend.srem( | 
| 52 | 
            +
                  def delete(role, suspect, object=nil)
         | 
| 53 | 
            +
                    @backend.srem(SUSPECT_ROLES_KEY % suspect_id(suspect), pack(role.to_s, object))
         | 
| 58 54 | 
             
                  end
         | 
| 59 55 |  | 
| 60 56 | 
             
                  def clear
         | 
| 61 57 | 
             
                    @backend.flushdb
         | 
| 62 58 | 
             
                  end
         | 
| 63 | 
            -
                  
         | 
| 64 | 
            -
                  private
         | 
| 65 | 
            -
                  
         | 
| 66 | 
            -
                  # Pack given permission data.
         | 
| 67 | 
            -
                  #
         | 
| 68 | 
            -
                  #   pack(foo)               # => "foo"
         | 
| 69 | 
            -
                  #   pack(foo, "FooClass")   # => "foo/FooClass"
         | 
| 70 | 
            -
                  #   pack(foo, FooClass.new) # => "foo/FooClass/{foo_object_ID}"
         | 
| 71 | 
            -
                  def pack(role, object=nil)
         | 
| 72 | 
            -
                    case object
         | 
| 73 | 
            -
                    when nil
         | 
| 74 | 
            -
                      "#{role}"
         | 
| 75 | 
            -
                    when Class 
         | 
| 76 | 
            -
                      "#{role}/#{object.name}"
         | 
| 77 | 
            -
                    else 
         | 
| 78 | 
            -
                      "#{role}/#{object.class.name}/#{object.id}"
         | 
| 79 | 
            -
                    end
         | 
| 80 | 
            -
                  end
         | 
| 81 | 
            -
                  
         | 
| 82 | 
            -
                  # Unpack given permission data.
         | 
| 83 | 
            -
                  def unpack(data)
         | 
| 84 | 
            -
                    data.to_s.split("/")
         | 
| 85 | 
            -
                  end
         | 
| 86 59 | 
             
                end # Redis
         | 
| 87 60 | 
             
              end # Store
         | 
| 88 61 | 
             
            end # Aclatraz
         | 
    
        data/lib/aclatraz/store/riak.rb
    CHANGED
    
    | @@ -1,11 +1,3 @@ | |
| 1 | 
            -
            require 'yaml'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            begin
         | 
| 4 | 
            -
              require "riak"
         | 
| 5 | 
            -
            rescue LoadError
         | 
| 6 | 
            -
              raise "You must install the redis-client gem to use the Riak store"
         | 
| 7 | 
            -
            end
         | 
| 8 | 
            -
             | 
| 9 1 | 
             
            module Aclatraz
         | 
| 10 2 | 
             
              module Store
         | 
| 11 3 | 
             
                # The most optimal way to store roles in riak database is pack everything
         | 
| @@ -17,41 +9,44 @@ module Aclatraz | |
| 17 9 | 
             
                class Riak
         | 
| 18 10 | 
             
                  include Aclatraz::Helpers
         | 
| 19 11 |  | 
| 20 | 
            -
                  def initialize(bucket_name, *args) | 
| 21 | 
            -
                     | 
| 22 | 
            -
                       | 
| 12 | 
            +
                  def initialize(bucket_name, *args)
         | 
| 13 | 
            +
                    require "riak" rescue raise LoadError, \
         | 
| 14 | 
            +
                      "You must install the `riak-client` gem to use Riak store"
         | 
| 15 | 
            +
                    
         | 
| 16 | 
            +
                    @backend = if args.first.respond_to?(:bucket)
         | 
| 17 | 
            +
                      args.first.bucket(bucket_name)
         | 
| 23 18 | 
             
                    else
         | 
| 24 | 
            -
                       | 
| 19 | 
            +
                      ::Riak::Client.new(*args).bucket(bucket_name)
         | 
| 25 20 | 
             
                    end
         | 
| 26 21 | 
             
                  end
         | 
| 27 22 |  | 
| 28 | 
            -
                  def set(role,  | 
| 29 | 
            -
                    obj = @backend.new(pack(role.to_s,  | 
| 23 | 
            +
                  def set(role, suspect, object=nil)
         | 
| 24 | 
            +
                    obj = @backend.new(pack(role.to_s, suspect_id(suspect), object))
         | 
| 30 25 | 
             
                    obj.content_type = "text/plain"
         | 
| 31 26 | 
             
                    obj.data = "1"
         | 
| 32 27 | 
             
                    obj.store
         | 
| 33 28 | 
             
                  end
         | 
| 34 29 |  | 
| 35 | 
            -
                  def roles( | 
| 30 | 
            +
                  def roles(suspect=nil)
         | 
| 36 31 | 
             
                    roles = []
         | 
| 37 32 | 
             
                    # Also this can be a little bit slow...
         | 
| 38 33 | 
             
                    @backend.keys.each do |key|
         | 
| 39 34 | 
             
                      @backend.exists?(key) ? perm = unpack(key) : next
         | 
| 40 | 
            -
                      if perm.size == 2 && (! | 
| 35 | 
            +
                      if perm.size == 2 && (!suspect || (suspect && perm[0].to_s == suspect_id(suspect)))
         | 
| 41 36 | 
             
                        roles.push(perm[1])
         | 
| 42 37 | 
             
                      end
         | 
| 43 38 | 
             
                    end
         | 
| 44 39 | 
             
                    roles.compact.uniq
         | 
| 45 40 | 
             
                  end
         | 
| 46 41 |  | 
| 47 | 
            -
                  def check(role,  | 
| 48 | 
            -
                    @backend.exists?(pack(role.to_s,  | 
| 49 | 
            -
                      object && !object.is_a?(Class) ? check(role,  | 
| 42 | 
            +
                  def check(role, suspect, object=nil)
         | 
| 43 | 
            +
                    @backend.exists?(pack(role.to_s, suspect_id(suspect), object)) or begin
         | 
| 44 | 
            +
                      object && !object.is_a?(Class) ? check(role, suspect, object.class) : false
         | 
| 50 45 | 
             
                    end
         | 
| 51 46 | 
             
                  end
         | 
| 52 47 |  | 
| 53 | 
            -
                  def delete(role,  | 
| 54 | 
            -
                    @backend.delete(pack(role.to_s,  | 
| 48 | 
            +
                  def delete(role, suspect, object=nil)
         | 
| 49 | 
            +
                    @backend.delete(pack(role.to_s, suspect_id(suspect), object))
         | 
| 55 50 | 
             
                  end
         | 
| 56 51 |  | 
| 57 52 | 
             
                  def clear
         | 
| @@ -60,27 +55,20 @@ module Aclatraz | |
| 60 55 | 
             
                    @backend.keys.each {|key| @backend.delete(key) }
         | 
| 61 56 | 
             
                  end
         | 
| 62 57 |  | 
| 63 | 
            -
                  private
         | 
| 64 | 
            -
             | 
| 65 58 | 
             
                  # Pack given permission data.
         | 
| 66 59 | 
             
                  #
         | 
| 67 60 | 
             
                  #   pack("foo", 10)               # => "10/foo"
         | 
| 68 61 | 
             
                  #   pack("foo", 10, "FooClass")   # => "10/foo/FooClass"
         | 
| 69 62 | 
             
                  #   pack("foo", 10, FooClass.new) # => "10/foo/FooClass/{foo_object_ID}"
         | 
| 70 | 
            -
                  def pack(role,  | 
| 63 | 
            +
                  def pack(role, suspect, object=nil)
         | 
| 71 64 | 
             
                    case object
         | 
| 72 65 | 
             
                    when nil
         | 
| 73 | 
            -
                       | 
| 66 | 
            +
                      [suspect, role]
         | 
| 74 67 | 
             
                    when Class 
         | 
| 75 | 
            -
                       | 
| 68 | 
            +
                      [suspect, role, object.name]
         | 
| 76 69 | 
             
                    else 
         | 
| 77 | 
            -
                       | 
| 78 | 
            -
                    end
         | 
| 79 | 
            -
                  end
         | 
| 80 | 
            -
                  
         | 
| 81 | 
            -
                  # Unpack given permission data.
         | 
| 82 | 
            -
                  def unpack(data)
         | 
| 83 | 
            -
                    data.to_s.split("/")
         | 
| 70 | 
            +
                      [suspect, role, object.class.name, object.id]
         | 
| 71 | 
            +
                    end.join("/")
         | 
| 84 72 | 
             
                  end
         | 
| 85 73 | 
             
                end # Riak
         | 
| 86 74 | 
             
              end # Store
         | 
    
        data/spec/aclatraz/guard_spec.rb
    CHANGED
    
    
| @@ -7,4 +7,21 @@ describe "Aclatraz helpers" do | |
| 7 7 | 
             
                camelize("foo_bar_bla").should == "FooBarBla"
         | 
| 8 8 | 
             
                camelize("foo").should == "Foo"
         | 
| 9 9 | 
             
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              it "#suspect_id should properly resolve id of given object" do 
         | 
| 12 | 
            +
                suspect_id("1").should == "1"
         | 
| 13 | 
            +
                suspect_id(1).should == "1"
         | 
| 14 | 
            +
                suspect_id(StubSuspect.new).should == "10"
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
              
         | 
| 17 | 
            +
              it "#unpack should properly split given string by /" do 
         | 
| 18 | 
            +
                unpack("foo/bar/10").should == %w[foo bar 10]
         | 
| 19 | 
            +
                unpack(nil).should == []
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              it "#pack should work properly" do 
         | 
| 23 | 
            +
                pack("admin").should == "admin"
         | 
| 24 | 
            +
                pack("admin", StubTarget).should == "admin/StubTarget"
         | 
| 25 | 
            +
                pack("admin", StubTarget.new).should == "admin/StubTarget/10"
         | 
| 26 | 
            +
              end
         | 
| 10 27 | 
             
            end
         | 
| @@ -55,7 +55,7 @@ describe "Aclatraz" do | |
| 55 55 | 
             
              let(:owner) { StubOwner.new }
         | 
| 56 56 | 
             
              let(:target) { StubTarget.new }
         | 
| 57 57 |  | 
| 58 | 
            -
               | 
| 58 | 
            +
              context "for Redis store" do 
         | 
| 59 59 | 
             
                subject { Aclatraz.init(:redis, "redis://localhost:6379/0") }
         | 
| 60 60 |  | 
| 61 61 | 
             
                class_eval &STORE_SPECS
         | 
| @@ -69,20 +69,32 @@ describe "Aclatraz" do | |
| 69 69 |  | 
| 70 70 | 
             
                it "shouls respect redis hash options given in init" do 
         | 
| 71 71 | 
             
                  Aclatraz.instance_variable_set("@store", nil)
         | 
| 72 | 
            -
                  Aclatraz.init(:redis, :url => "redis://localhost:6379/ | 
| 72 | 
            +
                  Aclatraz.init(:redis, :url => "redis://localhost:6379/2")
         | 
| 73 73 | 
             
                  Aclatraz.store.instance_variable_get('@backend').ping.should be_true
         | 
| 74 74 | 
             
                end 
         | 
| 75 75 | 
             
              end
         | 
| 76 76 |  | 
| 77 | 
            -
               | 
| 77 | 
            +
              context "for Riak store" do 
         | 
| 78 78 | 
             
                subject { Aclatraz.init(:riak, "roles") }
         | 
| 79 79 |  | 
| 80 80 | 
             
                class_eval &STORE_SPECS
         | 
| 81 81 |  | 
| 82 82 | 
             
                it "should respect persistent connection given on initalize" do 
         | 
| 83 83 | 
             
                  Aclatraz.instance_variable_set("@store", nil)
         | 
| 84 | 
            -
                  Aclatraz.init(:riak, "roles",  | 
| 84 | 
            +
                  Aclatraz.init(:riak, "roles", Riak::Client.new)
         | 
| 85 85 | 
             
                  Aclatraz.store.instance_variable_get('@backend').should be_kind_of(Riak::Bucket)
         | 
| 86 86 | 
             
                end
         | 
| 87 87 | 
             
              end
         | 
| 88 | 
            +
              
         | 
| 89 | 
            +
              context "for Cassandra store" do 
         | 
| 90 | 
            +
                subject { Aclatraz.init(:cassandra, "Super1", "Keyspace1") }
         | 
| 91 | 
            +
              
         | 
| 92 | 
            +
                class_eval &STORE_SPECS
         | 
| 93 | 
            +
              
         | 
| 94 | 
            +
                it "should respect persistent connection given on initialize" do 
         | 
| 95 | 
            +
                  Aclatraz.instance_variable_set("@store", nil)
         | 
| 96 | 
            +
                  Aclatraz.init(:cassandra, "Super1", Cassandra.new("Keyspace1"))
         | 
| 97 | 
            +
                  Aclatraz.store.instance_variable_get('@backend').should be_kind_of(Cassandra)
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 88 100 | 
             
            end
         | 
| @@ -38,7 +38,7 @@ describe "Aclatraz suspect" do | |
| 38 38 | 
             
                subject.roles.has?(:foobar3, target).should be_false
         | 
| 39 39 | 
             
              end
         | 
| 40 40 |  | 
| 41 | 
            -
               | 
| 41 | 
            +
              context "syntactic sugars" do 
         | 
| 42 42 | 
             
                it "1: should properly set given role" do 
         | 
| 43 43 | 
             
                  subject.is.foobar1!
         | 
| 44 44 | 
             
                  subject.is.foobar2_of!(StubTarget)
         | 
    
        data/spec/aclatraz_spec.rb
    CHANGED
    
    
    
        data/spec/alcatraz_bm.rb
    CHANGED
    
    | @@ -1,9 +1,3 @@ | |
| 1 | 
            -
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "aclatraz"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            Aclatraz.init :redis, "redis://localhost:6379/0"
         | 
| 6 | 
            -
             | 
| 7 1 | 
             
            class Account
         | 
| 8 2 | 
             
              include Aclatraz::Suspect
         | 
| 9 3 | 
             
              def id; 30; end
         | 
| @@ -42,12 +36,12 @@ $foo = Foo.new | |
| 42 36 | 
             
            ns = [1000, 2000, 5000, 10000]
         | 
| 43 37 |  | 
| 44 38 | 
             
            ns.each do |n|
         | 
| 45 | 
            -
              puts "#{n}  | 
| 39 | 
            +
              puts "#{n} operations:"
         | 
| 46 40 | 
             
              Benchmark.bm(10) do |bm| 
         | 
| 47 | 
            -
                bm.report("Assign:") { n.times {|x| $account. | 
| 48 | 
            -
                bm.report("Check:")  { n.times {|x| $account. | 
| 41 | 
            +
                bm.report("Assign:") { n.times {|x| $account.roles.assign("foo#{x}") } }
         | 
| 42 | 
            +
                bm.report("Check:")  { n.times {|x| $account.roles.has?("foo#{x}") } }
         | 
| 49 43 | 
             
                bm.report("Guard:")  { n.times {|x| $foo.test } }
         | 
| 50 | 
            -
                bm.report("Delete:") { n.times {|x| $account. | 
| 44 | 
            +
                bm.report("Delete:") { n.times {|x| $account.roles.delete("foo#{x}") } }
         | 
| 51 45 | 
             
              end
         | 
| 52 46 | 
             
              puts
         | 
| 53 47 | 
             
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: aclatraz
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 29
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 8 | 
             
              - 1
         | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0.1. | 
| 9 | 
            +
              - 3
         | 
| 10 | 
            +
              version: 0.1.3
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Kriss 'nu7hatch' Kowalik
         | 
| @@ -15,32 +15,46 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2010- | 
| 18 | 
            +
            date: 2010-10-16 00:00:00 +02:00
         | 
| 19 19 | 
             
            default_executable: 
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 22 | 
            -
              name:  | 
| 22 | 
            +
              name: dictionary
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 24 | 
             
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 25 25 | 
             
                none: false
         | 
| 26 26 | 
             
                requirements: 
         | 
| 27 | 
            -
                - -  | 
| 27 | 
            +
                - - ~>
         | 
| 28 28 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 29 | 
            -
                    hash:  | 
| 29 | 
            +
                    hash: 15
         | 
| 30 30 | 
             
                    segments: 
         | 
| 31 31 | 
             
                    - 1
         | 
| 32 | 
            +
                    - 0
         | 
| 33 | 
            +
                    version: "1.0"
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              version_requirements: *id001
         | 
| 36 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 37 | 
            +
              name: rspec
         | 
| 38 | 
            +
              prerelease: false
         | 
| 39 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 40 | 
            +
                none: false
         | 
| 41 | 
            +
                requirements: 
         | 
| 42 | 
            +
                - - ~>
         | 
| 43 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 44 | 
            +
                    hash: 3
         | 
| 45 | 
            +
                    segments: 
         | 
| 32 46 | 
             
                    - 2
         | 
| 33 | 
            -
                    -  | 
| 34 | 
            -
                    version:  | 
| 47 | 
            +
                    - 0
         | 
| 48 | 
            +
                    version: "2.0"
         | 
| 35 49 | 
             
              type: :development
         | 
| 36 | 
            -
              version_requirements: * | 
| 50 | 
            +
              version_requirements: *id002
         | 
| 37 51 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 38 52 | 
             
              name: mocha
         | 
| 39 53 | 
             
              prerelease: false
         | 
| 40 | 
            -
              requirement: & | 
| 54 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 41 55 | 
             
                none: false
         | 
| 42 56 | 
             
                requirements: 
         | 
| 43 | 
            -
                - -  | 
| 57 | 
            +
                - - ~>
         | 
| 44 58 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 45 59 | 
             
                    hash: 25
         | 
| 46 60 | 
             
                    segments: 
         | 
| @@ -48,11 +62,11 @@ dependencies: | |
| 48 62 | 
             
                    - 9
         | 
| 49 63 | 
             
                    version: "0.9"
         | 
| 50 64 | 
             
              type: :development
         | 
| 51 | 
            -
              version_requirements: * | 
| 65 | 
            +
              version_requirements: *id003
         | 
| 52 66 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 53 67 | 
             
              name: redis
         | 
| 54 68 | 
             
              prerelease: false
         | 
| 55 | 
            -
              requirement: & | 
| 69 | 
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 56 70 | 
             
                none: false
         | 
| 57 71 | 
             
                requirements: 
         | 
| 58 72 | 
             
                - - ~>
         | 
| @@ -63,11 +77,11 @@ dependencies: | |
| 63 77 | 
             
                    - 0
         | 
| 64 78 | 
             
                    version: "2.0"
         | 
| 65 79 | 
             
              type: :development
         | 
| 66 | 
            -
              version_requirements: * | 
| 80 | 
            +
              version_requirements: *id004
         | 
| 67 81 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 68 82 | 
             
              name: riak-client
         | 
| 69 83 | 
             
              prerelease: false
         | 
| 70 | 
            -
              requirement: & | 
| 84 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 71 85 | 
             
                none: false
         | 
| 72 86 | 
             
                requirements: 
         | 
| 73 87 | 
             
                - - ~>
         | 
| @@ -78,23 +92,23 @@ dependencies: | |
| 78 92 | 
             
                    - 8
         | 
| 79 93 | 
             
                    version: "0.8"
         | 
| 80 94 | 
             
              type: :development
         | 
| 81 | 
            -
              version_requirements: * | 
| 95 | 
            +
              version_requirements: *id005
         | 
| 82 96 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 83 | 
            -
              name:  | 
| 97 | 
            +
              name: cassandra
         | 
| 84 98 | 
             
              prerelease: false
         | 
| 85 | 
            -
              requirement: & | 
| 99 | 
            +
              requirement: &id006 !ruby/object:Gem::Requirement 
         | 
| 86 100 | 
             
                none: false
         | 
| 87 101 | 
             
                requirements: 
         | 
| 88 102 | 
             
                - - ~>
         | 
| 89 103 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 90 | 
            -
                    hash:  | 
| 104 | 
            +
                    hash: 27
         | 
| 91 105 | 
             
                    segments: 
         | 
| 92 | 
            -
                    - 1
         | 
| 93 106 | 
             
                    - 0
         | 
| 94 | 
            -
                     | 
| 95 | 
            -
             | 
| 96 | 
            -
               | 
| 97 | 
            -
             | 
| 107 | 
            +
                    - 8
         | 
| 108 | 
            +
                    version: "0.8"
         | 
| 109 | 
            +
              type: :development
         | 
| 110 | 
            +
              version_requirements: *id006
         | 
| 111 | 
            +
            description: "      Extremaly fast, flexible and intuitive access control mechanism, \n      powered by fast key value stores like Redis.\n"
         | 
| 98 112 | 
             
            email: kriss.kowalik@gmail.com
         | 
| 99 113 | 
             
            executables: []
         | 
| 100 114 |  | 
| @@ -119,6 +133,7 @@ files: | |
| 119 133 | 
             
            - lib/aclatraz/guard.rb
         | 
| 120 134 | 
             
            - lib/aclatraz/helpers.rb
         | 
| 121 135 | 
             
            - lib/aclatraz/store.rb
         | 
| 136 | 
            +
            - lib/aclatraz/store/cassandra.rb
         | 
| 122 137 | 
             
            - lib/aclatraz/store/redis.rb
         | 
| 123 138 | 
             
            - lib/aclatraz/store/riak.rb
         | 
| 124 139 | 
             
            - lib/aclatraz/suspect.rb
         | 
| @@ -129,7 +144,6 @@ files: | |
| 129 144 | 
             
            - spec/aclatraz/suspect_spec.rb
         | 
| 130 145 | 
             
            - spec/aclatraz_spec.rb
         | 
| 131 146 | 
             
            - spec/alcatraz_bm.rb
         | 
| 132 | 
            -
            - spec/spec.opts
         | 
| 133 147 | 
             
            - spec/spec_helper.rb
         | 
| 134 148 | 
             
            has_rdoc: true
         | 
| 135 149 | 
             
            homepage: http://github.com/nu7hatch/aclatraz
         | 
    
        data/spec/spec.opts
    DELETED