resourced 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - rbx-19mode
5
+ - jruby-19mode
6
+
7
+ branches:
8
+ only:
9
+ - master
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in resourced.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "rake"
8
+ gem "sqlite3"
9
+ gem "activerecord"
10
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrey Savchenko
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,75 @@
1
+ # Resourced
2
+
3
+ [![Build Status](https://travis-ci.org/Ptico/resourced.png)](https://travis-ci.org/Ptico/resourced)
4
+
5
+ Resourced adds a missing layer between model and controller.
6
+ It takes all parameter- and scope-related jobs from the model and makes your model thin. Here is example:
7
+
8
+ ```ruby
9
+ class PostResource
10
+ include Resourced::ActiveRecord
11
+
12
+ model Post
13
+ key :id
14
+
15
+ params do
16
+ allow :title, :body, :tags
17
+ allow :category, if: -> { scope.admin? }
18
+ end
19
+
20
+ finders do
21
+ restrict :search, if: -> { scope.guest? }
22
+
23
+ finder :title do |val|
24
+ chain.where(title: val)
25
+ end
26
+
27
+ finder :search do |val|
28
+ chain.where(t[:body].matches("%#{val}%"))
29
+ end
30
+ end
31
+ end
32
+ ```
33
+
34
+ Now you can do following:
35
+
36
+ ```ruby
37
+ before_filter do
38
+ posts = PostResource.new(params, current_user)
39
+ end
40
+
41
+ # Let params: { title: "My first post", body: "Lorem ipsum" }
42
+ post = posts.build
43
+ post # => #<Post id: nil, title: "My first post", body: "Lorem ipsum", category: nil>
44
+
45
+ # Let params: { id: 2, title: "My awesome post" }
46
+ posts.update! # Will update title for post with id 2
47
+ posts.first # Will find first post with title "My awesome post"
48
+
49
+ # Let params: { search: "Atlas Shrugged" }
50
+ posts.all # Will return all posts which contains "Atlas Shrugged" unless current user is guest
51
+ ```
52
+
53
+ ## Installation
54
+
55
+ Add this line to your application's Gemfile:
56
+
57
+ gem 'resourced'
58
+
59
+ And then execute:
60
+
61
+ $ bundle
62
+
63
+ Or install it yourself as:
64
+
65
+ $ gem install resourced
66
+
67
+ ## Usage
68
+
69
+ ## Contributing
70
+
71
+ 1. Fork it
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 4. Push to the branch (`git push origin my-new-feature`)
75
+ 5. Create new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => :spec
5
+
6
+ desc "Test switcher"
7
+ RSpec::Core::RakeTask.new('spec')
@@ -0,0 +1,71 @@
1
+ require "resourced/version"
2
+ require "resourced/params"
3
+ require "resourced/finders"
4
+
5
+ module Resourced
6
+ module Facade
7
+ module InstanceMethods
8
+ def initialize(params, scope)
9
+ @scope = scope
10
+ @model = self.class.instance_variable_get(:@model)
11
+ @key = self.class.instance_variable_get(:@key)
12
+ @chain = @model
13
+ super
14
+ @body = @params.keep_if { |k, v| attribute_names.include?(k) }
15
+ end
16
+ attr_accessor :params, :scope
17
+ attr_reader :model, :chain, :key
18
+
19
+ ##
20
+ # Run external code in context of facade
21
+ #
22
+ # Examples:
23
+ #
24
+ # resource = UserResource.new(params, scope)
25
+ # subj = "john"
26
+ # resource.context do
27
+ # chain.where(name: subj)
28
+ # end
29
+ #
30
+ def context(&block)
31
+ if block_given?
32
+ @chain = self.instance_eval(&block)
33
+ end
34
+
35
+ self
36
+ end
37
+ end
38
+
39
+ module ClassMethods
40
+ ##
41
+ # Set or get model class
42
+ #
43
+ def model(model_class=nil)
44
+ model_class ? @model = model_class : @model
45
+ end
46
+
47
+ ##
48
+ # Duplicate facade and set another model class
49
+ #
50
+ def [](model_class)
51
+ klass = self.dup
52
+ klass.instance_variable_set(:@model, model_class)
53
+ klass
54
+ end
55
+
56
+ ##
57
+ # Set primary key
58
+ #
59
+ def key(key_name=nil)
60
+ key_name ? @key = key_name.to_sym : @key
61
+ end
62
+ end
63
+
64
+ def self.included(base)
65
+ base.send(:include, Resourced::Params)
66
+ base.send(:include, Resourced::Finders)
67
+ base.send(:include, InstanceMethods)
68
+ base.extend ClassMethods
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,36 @@
1
+ require "resourced"
2
+ require "resourced/active_record/meta"
3
+ require "resourced/active_record/proxy"
4
+ require "resourced/active_record/actions"
5
+
6
+ module Resourced
7
+ module ActiveRecord
8
+
9
+ module Helpers
10
+ def t
11
+ @table ||= model.arel_table
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ def key(key_name=nil)
17
+ super
18
+ key_name = key_name.to_sym
19
+ finders do
20
+ finder key_name do |v|
21
+ chain.where(key_name => v)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.included(base)
28
+ base.send(:include, Resourced::Facade)
29
+ base.send(:include, Meta)
30
+ base.send(:include, Proxy)
31
+ base.send(:include, Actions)
32
+ base.extend ClassMethods
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module Resourced
2
+ module ActiveRecord
3
+
4
+ module Actions
5
+ def build
6
+ model.new(@body)
7
+ end
8
+
9
+ def update
10
+ body = @body.reject { |k,_| k == :id }
11
+
12
+ collection = if params[key]
13
+ [model.find(params[key])]
14
+ else
15
+ all
16
+ end
17
+
18
+ collection.map do |obj|
19
+ obj.assign_attributes(body)
20
+ obj
21
+ end
22
+ end
23
+
24
+ def update!
25
+ body = @body.reject { |k,_| k == :id }
26
+
27
+ collection = if params[key]
28
+ [model.find(params[key])]
29
+ else
30
+ all
31
+ end
32
+
33
+ collection.map do |obj|
34
+ obj.update_attributes(body)
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module Resourced
2
+
3
+ module ActiveRecord
4
+ module Meta
5
+ def attributes
6
+ @attributes ||= Hash[model.columns.map{ |c| [c.name.to_sym, c.type] }]
7
+ end
8
+
9
+ def attribute_names
10
+ attributes.keys
11
+ end
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,35 @@
1
+ module Resourced
2
+
3
+ module ActiveRecord
4
+
5
+ module Proxy
6
+ include Enumerable
7
+
8
+ def first
9
+ apply_finders.chain.first
10
+ end
11
+
12
+ def last
13
+ apply_finders.chain.last
14
+ end
15
+
16
+ def all
17
+ apply_finders.chain.all
18
+ end
19
+
20
+ def each(&block)
21
+ all.each(&block)
22
+ end
23
+
24
+ def as_json(*args)
25
+ all.as_json(*args)
26
+ end
27
+
28
+ def to_json(*args)
29
+ all.to_json(*args)
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,78 @@
1
+ require "resourced/params"
2
+
3
+ module Resourced
4
+ module Finders
5
+ class Finders < Resourced::Params::RuleSet
6
+ def initialize
7
+ super
8
+ @finders = {}
9
+ end
10
+ attr_reader :finders
11
+
12
+ ##
13
+ # Add finder
14
+ #
15
+ # Params:
16
+ # - name {Symbol} Finder key
17
+ # - options {Hash} Finder options (optional, default: {})
18
+ # - default Default value
19
+ # - if {Proc|Symbol} Condition for finder, should return Boolean
20
+ #
21
+ # Examples:
22
+ #
23
+ # finder :limit, default: 20 do |val|
24
+ # chain.limit(val)
25
+ # end
26
+ #
27
+ # Yields: Block with finder/filtration logic with a given parameter value
28
+ #
29
+ def finder(name, options={}, &block)
30
+ name = name.to_sym
31
+
32
+ allow(name, options)
33
+ @finders[name] = block
34
+
35
+ self
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ def initialize(params, scope)
41
+ super
42
+ @finders_obj = self.class.instance_variable_get(:@_finders_obj)
43
+ @finders = @finders_obj.sanitize_params(chain, params)
44
+
45
+ defaults = self.class.instance_variable_get(:@_default_finders)
46
+ defaults.each do |finder|
47
+ context(&finder)
48
+ end
49
+ end
50
+
51
+ def apply_finders
52
+ @finders.each_pair do |key, value|
53
+ @chain = self.instance_exec(value, &@finders_obj.finders[key.to_sym])
54
+ end
55
+
56
+ return self
57
+ end
58
+ end
59
+
60
+ module ClassMethods
61
+ def finders(&block)
62
+ @_finders_obj ||= Finders.new
63
+ @_finders_obj.instance_eval(&block)
64
+ end
65
+ attr_reader :_finders_obj
66
+
67
+ def default_finder(&block)
68
+ @_default_finders << block if block_given?
69
+ end
70
+ end
71
+
72
+ def self.included(base)
73
+ base.instance_variable_set(:@_default_finders, [])
74
+ base.extend ClassMethods
75
+ base.send(:include, InstanceMethods)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,179 @@
1
+ require "active_support/core_ext/array"
2
+
3
+ module Resourced
4
+ module Params
5
+
6
+ module InstanceMethods
7
+ def initialize(params, scope)
8
+ set(params)
9
+ end
10
+
11
+ ##
12
+ # Set additional params
13
+ #
14
+ # Params:
15
+ # - params {Hash} List of params to be assigned
16
+ #
17
+ # Examples:
18
+ #
19
+ # resource = UserResource.new(params, scope)
20
+ # resource.set(role: "guest")
21
+ #
22
+ def set(params={})
23
+ sanitized = self.class._params_obj.sanitize_params(self, params)
24
+
25
+ if @params
26
+ @params.merge(sanitized)
27
+ else
28
+ @params = sanitized
29
+ end
30
+
31
+ self
32
+ end
33
+
34
+ ##
35
+ # Erase existing params
36
+ #
37
+ # Params:
38
+ # - params {Hash} List of param keys to be erased
39
+ #
40
+ # Examples:
41
+ #
42
+ # resource = UserResource.new(params, scope)
43
+ # resource.erase(:password, :auth_token)
44
+ #
45
+ def erase(*keys)
46
+ keys.each do |key|
47
+ @params.delete(key.to_sym)
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ protected
54
+
55
+ def params
56
+ @params
57
+ end
58
+ end
59
+
60
+ class RuleSet
61
+ def initialize
62
+ @defaults = {}
63
+ @conditional_allows = []
64
+ @unconditional_allows = []
65
+ @conditional_restricts = []
66
+ @unconditional_restricts = []
67
+ end
68
+ attr_reader :defaults
69
+
70
+ ##
71
+ # Allow field(s) to be assigned
72
+ #
73
+ # Options:
74
+ # - default Default value
75
+ # - if {Proc} Condition for allowing, should return Boolean
76
+ #
77
+ # Examples:
78
+ #
79
+ # allow :name, :email, if: -> { scope == :admin }
80
+ # allow :role, default: "guest"
81
+ #
82
+ def allow(*fields)
83
+ opts = fields.extract_options! # AS
84
+
85
+ if opts[:if]
86
+ @conditional_allows << ConditionalGroup.new(opts[:if], fields)
87
+ else
88
+ @unconditional_allows += fields
89
+ end
90
+
91
+ if opts[:default]
92
+ fields.each do |field|
93
+ @defaults[field] = opts[:default]
94
+ end
95
+ end
96
+
97
+ self
98
+ end
99
+
100
+ ##
101
+ # Restrict allowed fields
102
+ #
103
+ # Options:
104
+ # - if {Proc} Condition for restriction, should return Boolean
105
+ #
106
+ # Examples:
107
+ #
108
+ # restrict :role, if: -> { scope !== :admin }
109
+ #
110
+ def restrict(*fields)
111
+ opts = fields.extract_options! # AS
112
+
113
+ if opts[:if]
114
+ @conditional_restricts << ConditionalGroup.new(opts[:if], fields)
115
+ else
116
+ @unconditional_restricts += fields
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ def sanitize_params(context, params)
123
+ allowed_params = @unconditional_allows
124
+
125
+ @conditional_allows.each do |cond|
126
+ if cond.test(context)
127
+ allowed_params += cond.fields
128
+ end
129
+ end
130
+
131
+ allowed_params.uniq!
132
+
133
+ allowed_params -= @unconditional_restricts
134
+
135
+ @conditional_restricts.each do |cond|
136
+ if cond.test(context)
137
+ allowed_params -= cond.fields
138
+ end
139
+ end
140
+
141
+ @defaults.merge(params).symbolize_keys.keep_if { |k, v| allowed_params.include?(k) } # AS
142
+ end
143
+ end
144
+
145
+ class ConditionalGroup
146
+ def initialize(condition, fields)
147
+ @condition = case condition
148
+ when Symbol, String
149
+ lambda { send(condition.to_sym) }
150
+ when Proc
151
+ condition
152
+ end
153
+
154
+ @fields = fields
155
+ end
156
+
157
+ attr_reader :fields
158
+
159
+ def test(context)
160
+ !!context.instance_exec(&@condition)
161
+ end
162
+ end
163
+
164
+ module ClassMethods
165
+ def params(&block)
166
+ @_params_obj ||= RuleSet.new
167
+ @_params_obj.instance_eval(&block)
168
+ end
169
+
170
+ attr_reader :_params_obj
171
+ end
172
+
173
+ include InstanceMethods
174
+
175
+ def self.included(base)
176
+ base.extend ClassMethods
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,3 @@
1
+ module Resourced
2
+ VERSION = "0.0.1.beta1"
3
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'resourced/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "resourced"
8
+ gem.version = Resourced::VERSION
9
+ gem.authors = ["Andrey Savchenko"]
10
+ gem.email = ["andrey@aejis.eu"]
11
+ gem.description = %q{WIP - not for production}
12
+ gem.summary = %q{Missing layer between model and controller}
13
+ gem.homepage = "https://github.com/Ptico/resourced"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency "active_support"
20
+ gem.add_development_dependency "rspec"
21
+ end
@@ -0,0 +1,103 @@
1
+ require "spec_helper"
2
+ require "support/active_record"
3
+
4
+ require "active_record"
5
+ require "resourced/active_record"
6
+
7
+ describe Resourced::ActiveRecord do
8
+ before :each do
9
+ setup_db
10
+ end
11
+
12
+ after :each do
13
+ teardown_db
14
+ end
15
+
16
+ class User < ActiveRecord::Base; end;
17
+
18
+ let(:klass) do
19
+ Class.new do
20
+ include Resourced::ActiveRecord
21
+
22
+ model User
23
+ key :id
24
+
25
+ params do
26
+ allow :name, :email
27
+ allow :role, :if => lambda { scope == "admin" }
28
+ end
29
+
30
+ finders do
31
+ finder :name do |v|
32
+ chain.where(:name => v)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "Create" do
39
+ it "should filter params" do
40
+ inst = klass.new({ :name => "Peter", :email => "peter@test.com", :role => "admin" }, "")
41
+ attrs = inst.build.attributes
42
+
43
+ attrs["name"].should eq("Peter")
44
+ attrs["role"].should be_nil
45
+ end
46
+ end
47
+
48
+ describe "Read" do
49
+ before :each do
50
+ add_user 1, "Homer", "homer@test.com", "admin"
51
+ add_user 2, "Bart", "bart@test.com", "user"
52
+ add_user 3, "Lisa", "lisa@test.com", "user"
53
+ end
54
+
55
+ it "should find by pkey" do
56
+ inst = klass.new({ :id => 3 }, "")
57
+
58
+ inst.first.name.should eq("Lisa")
59
+ end
60
+
61
+ it "should find with finder" do
62
+ inst = klass.new({ :name => "Bart" }, "")
63
+
64
+ inst.first.email.should eq("bart@test.com")
65
+ end
66
+
67
+ it "should iterate over results with #map" do
68
+ inst = klass.new({}, "")
69
+
70
+ result = inst.map do |user|
71
+ user.name
72
+ end
73
+
74
+ result.should eq(%w(Homer Bart Lisa))
75
+ end
76
+ end
77
+
78
+ describe "Update" do
79
+ before :each do
80
+ add_user 1, "Homer", "homer@test.com", "admin"
81
+ add_user 2, "Bart", "bart@test.com", "user"
82
+ add_user 3, "Lisa", "lisa@test.com", "user"
83
+ end
84
+
85
+ it "should prepare collection to update" do
86
+ inst = klass.new({ :id => [2, 3], :role => "guest" }, "admin")
87
+
88
+ collection = inst.update
89
+
90
+ collection.map{ |u| u.role }.should eq(["guest", "guest"])
91
+ end
92
+
93
+ it "should update the record immediatly" do
94
+ inst = klass.new({ :id => [2, 3], :role => "guest" }, "admin")
95
+
96
+ inst.update!
97
+
98
+ User.find(2).role.should eq("guest")
99
+ User.find(3).role.should eq("guest")
100
+ end
101
+ end
102
+
103
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+
3
+ describe Resourced::Finders do
4
+ class FindersTestRelation
5
+ def initialize
6
+ @result = ""
7
+ end
8
+ attr_reader :result
9
+
10
+ def method_missing(name, value)
11
+ @result += "##{name}(#{value})"
12
+ self
13
+ end
14
+ end
15
+
16
+ # Workaround
17
+ class FinderSuper; def initialize(*args); end; end
18
+
19
+ let(:klass) {
20
+ Class.new(FinderSuper) do
21
+ include Resourced::Finders
22
+
23
+ def initialize(params={}, scope="guest")
24
+ super
25
+ @scope = scope
26
+ @chain = FindersTestRelation.new
27
+ end
28
+ attr_reader :chain
29
+ end
30
+ }
31
+ let(:inst) { klass.new(params) }
32
+
33
+ describe "Basic finder" do
34
+ before :each do
35
+ klass.finders do
36
+ finder :offset do |val|
37
+ chain.offset(val)
38
+ end
39
+ end
40
+ end
41
+
42
+ context "with given corresponding parameters" do
43
+ let(:params) { {:offset => 2} }
44
+
45
+ it "should be called" do
46
+ inst.apply_finders.chain.result.should eq("#offset(2)")
47
+ end
48
+ end
49
+
50
+ context "without corresponding parameters" do
51
+ let(:params) { {} }
52
+
53
+ it "should not be called" do
54
+ inst.apply_finders.chain.result.should eq("")
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "Finder with default" do
60
+ before :each do
61
+ klass.finders do
62
+ finder :limit, :default => 10 do |val|
63
+ chain.limit(val)
64
+ end
65
+ end
66
+ end
67
+
68
+ context "when finder not specified" do
69
+ let(:params) { {} }
70
+
71
+ it { inst.apply_finders.chain.result.should eq("#limit(10)") }
72
+ end
73
+
74
+ context "when finder specified" do
75
+ let(:params) { {:limit => 20} }
76
+
77
+ it { inst.apply_finders.chain.result.should eq("#limit(20)") }
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ describe Resourced::Params do
4
+ class ParamsTest
5
+ include Resourced::Params
6
+
7
+ def initialize(params, scope)
8
+ @scope = scope
9
+ super
10
+ end
11
+ attr_reader :params
12
+ end
13
+
14
+ params = { :a => 1, :b => 2, :c => 3, :d => 4 }
15
+
16
+ describe "Unconditional allows" do
17
+ klass = ParamsTest.dup
18
+ klass.params do
19
+ allow :a, :b, :c
20
+ end
21
+ inst = klass.new(params, "admin")
22
+
23
+ it "should contain only allowed" do
24
+ inst.params.keys.should eq([:a, :b, :c])
25
+ end
26
+ end
27
+
28
+ describe "Conditional allows" do
29
+ klass = ParamsTest.dup
30
+
31
+ klass.params do
32
+ allow :a, :b, :c
33
+ allow :d, :if => lambda { @scope == "admin" }
34
+ end
35
+
36
+ context "when condition matches" do
37
+ inst = klass.new(params, "admin")
38
+
39
+ it "should contain conditional param" do
40
+ inst.params.keys.should eq([:a, :b, :c, :d])
41
+ end
42
+ end
43
+
44
+ context "when condition not matches" do
45
+ inst = klass.new(params, "guest")
46
+
47
+ it "should not contain conditional param" do
48
+ inst.params.keys.should eq([:a, :b, :c])
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "Unconditional restricts" do
54
+ klass = ParamsTest.dup
55
+ klass.params do
56
+ allow :a, :b, :c
57
+ restrict :c
58
+ end
59
+ inst = klass.new(params, "admin")
60
+
61
+ it "should not contain restricted" do
62
+ inst.params.keys.should eq([:a, :b])
63
+ end
64
+ end
65
+
66
+ describe "Conditional restricts" do
67
+ klass = ParamsTest.dup
68
+ klass.params do
69
+ allow :a, :b, :c
70
+ restrict :c, :if => lambda { @scope != "admin" }
71
+ end
72
+
73
+ context "when condition matches" do
74
+ inst = klass.new(params, "guest")
75
+
76
+ it "should not contain conditional param" do
77
+ inst.params.keys.should eq([:a, :b])
78
+ end
79
+ end
80
+
81
+ context "when condition not matches" do
82
+ inst = klass.new(params, "admin")
83
+
84
+ it "should contain conditional param" do
85
+ inst.params.keys.should eq([:a, :b, :c])
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,19 @@
1
+ require "resourced"
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # Require this file using `require "spec_helper"` to ensure that it is only
6
+ # loaded once.
7
+ #
8
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ # Run specs in random order to surface order dependencies. If you find an
15
+ # order dependency and want to debug it, you can fix the order by providing
16
+ # the seed, which is printed after each run.
17
+ # --seed 1234
18
+ config.order = 'random'
19
+ end
@@ -0,0 +1,22 @@
1
+ def setup_db
2
+ FileUtils.rm("test.sqlite3") if File.exists?("test.sqlite3")
3
+
4
+ ActiveRecord::Migration.verbose = false
5
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "test.sqlite3")
6
+
7
+ ActiveRecord::Schema.define do
8
+ create_table :users, :force => true do |t|
9
+ t.string :name
10
+ t.string :email
11
+ t.string :role
12
+ end
13
+ end
14
+ end
15
+
16
+ def teardown_db
17
+ FileUtils.rm("test.sqlite3") if File.exists?("test.sqlite3")
18
+ end
19
+
20
+ def add_user(id, name, email, role)
21
+ ActiveRecord::Base.connection.execute("INSERT INTO users (id, name, email, role) VALUES (#{id}, '#{name}', '#{email}', '#{role}')")
22
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resourced
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Andrey Savchenko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_support
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: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
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
+ description: WIP - not for production
47
+ email:
48
+ - andrey@aejis.eu
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rspec
55
+ - .travis.yml
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - lib/resourced.rb
61
+ - lib/resourced/active_record.rb
62
+ - lib/resourced/active_record/actions.rb
63
+ - lib/resourced/active_record/meta.rb
64
+ - lib/resourced/active_record/proxy.rb
65
+ - lib/resourced/finders.rb
66
+ - lib/resourced/params.rb
67
+ - lib/resourced/version.rb
68
+ - resourced.gemspec
69
+ - spec/resourced/adapters/active_record_spec.rb
70
+ - spec/resourced/finders_spec.rb
71
+ - spec/resourced/params_spec.rb
72
+ - spec/spec_helper.rb
73
+ - spec/support/active_record.rb
74
+ homepage: https://github.com/Ptico/resourced
75
+ licenses: []
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>'
90
+ - !ruby/object:Gem::Version
91
+ version: 1.3.1
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 1.8.23
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Missing layer between model and controller
98
+ test_files:
99
+ - spec/resourced/adapters/active_record_spec.rb
100
+ - spec/resourced/finders_spec.rb
101
+ - spec/resourced/params_spec.rb
102
+ - spec/spec_helper.rb
103
+ - spec/support/active_record.rb