resourced 0.0.1.beta1

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