provision 0.0.1

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/.gitignore ADDED
@@ -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 @@
1
+ --color
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## v0.0.1
2
+
3
+ * initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in provision.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Chen Fisher
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.
data/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # Provision
2
+
3
+ The provision gem lets you hook a provision filter to a method. **ANY method**.
4
+
5
+ For example,
6
+ Lets say we have an article website, where users can post articles.
7
+
8
+ We want to limit the number of articles a user can post to our website, based on a primium account. For example, if the user is using the free version he can post up to 5 articles, when a user that has paid and is using the pro account, can post up to 20 articles.
9
+
10
+ This is where 'provision' comes in. It makes it easy and dry to do provisions on your website.
11
+
12
+ The great thing about **provision** is that it can act on any level - model, controller or any other class you have.
13
+ Think of it as ActiveRecord's **validate** and Controller's **before_filter** combined and available on any class and method.
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'provision'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install provision
29
+
30
+ ## Usage
31
+ When a method is provisioned, whenever it is called, the provision method comes into action.
32
+ If the provision method returns true then the original method will be called. If the provision returns false
33
+ then the method won't be called (and false will be returned)
34
+
35
+ ### Provision using a method
36
+ class SomeClass
37
+ def a_method
38
+ # do something
39
+ end
40
+ provision :a_method, :with => :provision_method
41
+
42
+ private
43
+ def provision_method
44
+ # some condition (returns true or false)
45
+ end
46
+ end
47
+
48
+ **provision_method** can take optional ***args** which are the arguments passed to the original method:
49
+
50
+ def provision_method(*args)
51
+ # some condition using args
52
+ end
53
+
54
+
55
+ ### Provision using a proc (lambda)
56
+ class SomeClass
57
+ def a_method
58
+ # do something
59
+ end
60
+ provision :a_method, :with => lambda{ [some condition] }
61
+ end
62
+
63
+ **lambda** can take arguments like so:
64
+
65
+ provision :a_method, :with => lambda{ |sender, *args| [some condition] }
66
+ where **sender** is the instance of SomeClass and ***args** are the arguments passed to the original method
67
+
68
+
69
+ ### Provision using a class name
70
+ class SomeClass
71
+ def a_method
72
+ # do something
73
+ end
74
+ provision :a_method, :with => ProvisionClass
75
+ end
76
+
77
+ **NOTE**: provision will try to call `ProvisionClass.provision!` (a class method); if the class does not respond to provision! then
78
+ it will create an instance of ProvisionClass and then call `provision!` (mind the bang!)
79
+
80
+ class ProvisionClass
81
+ def self.provision!(sender, *args)
82
+ # some condition using sender and *args
83
+ end
84
+ end
85
+
86
+ **sender** is the instance of SomeClass and ***args** are the arguments passed to the original method
87
+
88
+ ### Provision using an instance of a class
89
+ when the **lambda** block return something other than *true* or *false* then provision assumes it returns an instance
90
+ of a class that responds to **provision!**
91
+
92
+ provision :a_method, :with => lambda{ |sender, *args| ProvisionClass.new(sender, *args) }
93
+
94
+ **sender** and ***args** are optional
95
+
96
+ ### Add a block to do something
97
+ You can add a block which will be called when the provision returns false.
98
+
99
+ provision :a_method, :with => lambda{ some_condition } do |sender, *args|
100
+ # do something for when the provision fails
101
+ # for example: send a notification email to the user you just provisioned
102
+ end
103
+
104
+ **sender** and ***args** are optional
105
+
106
+ ### Provision more than one method at a time
107
+ You can pass any number of methods to be provisioned
108
+
109
+ provision :a_method, :another_method, :with => lambda{ some_condition } do
110
+ # do something
111
+ end
112
+
113
+ ### Use it in your controllers and models
114
+ You can use it in your controllers and models like you use before_filter and validations.
115
+ Lets provision a user on the number of posts they can post. We can do this on the controller level or on the model level:
116
+
117
+ #### Controller level example:
118
+ class PostsController < ApplicationController
119
+ include provision
120
+
121
+ def create
122
+ # create the post
123
+ end
124
+
125
+ provision :create, :with => UserProvision do |controller|
126
+ controller.flash[:error] = "You have maxed out your posts"
127
+ redirect_to some_url
128
+ end
129
+ end
130
+
131
+ class UserProvision
132
+ def self.provision!(controller)
133
+ controller.current_user.post_count < MAX_POSTS
134
+ end
135
+ end
136
+
137
+ #### Model level example:
138
+ class Post < ActiveRecord::Base
139
+ include provision
140
+
141
+ provision :save, :valid?, :with => lambda{ |post| post.user.post_count < MAX_COUNT } do |post|
142
+ post.errors[:count] = "you have maxed out you post count"
143
+ false
144
+ end
145
+ end
146
+
147
+ ## GOTCHA!
148
+ `provision` call **must** come **after** your provisioned method definitions
149
+
150
+
151
+ ## Contributing
152
+
153
+ 1. Fork it
154
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
155
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
156
+ 4. Push to the branch (`git push origin my-new-feature`)
157
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,3 @@
1
+ module Provision
2
+ VERSION = "0.0.1"
3
+ end
data/lib/provision.rb ADDED
@@ -0,0 +1,94 @@
1
+ require "provision/version"
2
+
3
+ module Provision
4
+ module ClassMethods
5
+
6
+ ##
7
+ #
8
+ def provision(*args, &block)
9
+ options = args.last.is_a?(::Hash) ? args.pop : {}
10
+
11
+ hook(*args, :before => options[:with], &block)
12
+ end
13
+
14
+ ##
15
+ # hooks the specified array of methods to a method specified with the :before hook
16
+ # calls the original method only if the hooked method returns true
17
+ # usage:
18
+ # hook :method1, :method2, :before => :method_name
19
+ def hook(*args, &block)
20
+ hooks = args.last.is_a?(::Hash) ? args.pop : {}
21
+
22
+ args.each do |method|
23
+ original_method = self.instance_method(method)
24
+
25
+ self.send(:define_method, method) do |*a|
26
+ return original_method.bind(self).call(*a) if
27
+ case
28
+ when hooks[:before].is_a?(Symbol)
29
+ hook_method(hooks[:before], *a)
30
+ when hooks[:before].is_a?(Class)
31
+ hook_class(hooks[:before], *a)
32
+ when hooks[:before].is_a?(Proc)
33
+ hook_proc(hooks[:before], *a)
34
+ when hooks[:before].instance_of?(hooks[:before].class)
35
+ hook_instance(hooks[:before], *a)
36
+ end
37
+
38
+ if block_given?
39
+ if block.arity == 0
40
+ return yield
41
+ else
42
+ return yield(self, *a)
43
+ end
44
+ end
45
+
46
+ false
47
+ end
48
+ end
49
+ end
50
+
51
+ private :hook
52
+ end
53
+
54
+ module InstanceMethods
55
+ def hook_method(h, *a)
56
+ self.send(h, *a)
57
+ end
58
+
59
+ def hook_class(h, *a)
60
+ if h.respond_to? :provision!
61
+ h.provision!(self, *a)
62
+ else
63
+ h.new.provision!(self, *a)
64
+ end
65
+ end
66
+
67
+ def hook_instance(h, *a)
68
+ h.provision!(self, *a)
69
+ end
70
+
71
+ def hook_proc(h, *a)
72
+ # call the proc
73
+ if h.arity == 0
74
+ result = h.call
75
+ else
76
+ result = h.call(self, *a)
77
+ end
78
+
79
+ # if proc returns true or false then return the result
80
+ return result if result == true || result == false
81
+
82
+ # if proc returns an instance of an object then call provision! on it
83
+ result.provision!(*a)
84
+ end
85
+
86
+ private :hook_method, :hook_class, :hook_instance, :hook_proc
87
+
88
+ end
89
+
90
+ def self.included(receiver)
91
+ receiver.extend ClassMethods
92
+ receiver.send :include, InstanceMethods
93
+ end
94
+ end
data/provision.gemspec ADDED
@@ -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 'provision/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "provision"
8
+ gem.version = Provision::VERSION
9
+ gem.authors = ["Chen Fisher"]
10
+ gem.email = ["chen.fisher@gmail.com"]
11
+ gem.description = %q{Lets one hook a provision for a method}
12
+ gem.summary = %q{When a method is provisioned, any call to that method is passed through a provision filter that can stop the method execution and perform some actions}
13
+ gem.homepage = "https://github.com/chenfisher/provision"
14
+
15
+ gem.add_development_dependency "rspec"
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,3 @@
1
+ class Sample
2
+ include Provision
3
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'provision/sample'
3
+
4
+ describe Provision do
5
+
6
+ before :each do
7
+ @sample = Sample.new
8
+ @sample.stub(:a_method).and_return('hello')
9
+ @meta = class << @sample; self; end
10
+ end
11
+
12
+ it "should call the method if provision returns true" do
13
+ @sample.stub(:this_method).and_return(true)
14
+ @meta.provision :a_method, :with => :this_method
15
+
16
+ @sample.a_method.should eq 'hello'
17
+ end
18
+
19
+ it "should provision a method using a method name" do
20
+ @sample.stub(:this_method).and_return(false)
21
+ @meta.provision :a_method, :with => :this_method
22
+
23
+ @sample.a_method.should_not eq 'hello'
24
+ end
25
+
26
+ it "should provision a method using a class name" do
27
+ class ThisClass;
28
+ def provision!(sender)
29
+ false
30
+ end
31
+ end
32
+
33
+ @meta.provision :a_method, :with => ThisClass
34
+
35
+ @sample.a_method.should_not eq 'hello'
36
+ end
37
+
38
+ it "should provision a method using a class name with class method provision!" do
39
+ class ThisClass;
40
+ def self.provision!(sender)
41
+ false
42
+ end
43
+ end
44
+
45
+ @meta.provision :a_method, :with => ThisClass
46
+
47
+ @sample.a_method.should_not eq 'hello'
48
+ end
49
+
50
+ it "should provision a method using an instance of a class" do
51
+ class ThisClass; end
52
+ @instance = ThisClass.new
53
+ @instance.stub(:provision!).and_return false
54
+ @instance.should_receive(:provision!)
55
+
56
+ @meta.provision :a_method, :with => @instance
57
+
58
+ @sample.a_method.should_not eq 'hello'
59
+ end
60
+
61
+ it "should provision a method using an instance of a class (from a proc)" do
62
+ class ThisClass; end
63
+ ThisClass.any_instance.stub(:provision!).and_return false
64
+ ThisClass.any_instance.should_receive(:provision!)
65
+
66
+ @meta.provision :a_method, :with => lambda{ ThisClass.new }
67
+
68
+ @sample.a_method.should_not eq 'hello'
69
+ end
70
+
71
+ it "should provision a method using a proc" do
72
+ @meta.provision :a_method, :with => lambda{ false }
73
+
74
+ @sample.a_method.should_not eq 'hello'
75
+ end
76
+
77
+ it "should takea proc with arguments" do
78
+ @meta.provision :a_method, :with => lambda{ |sender, p| sender === @sample && p == 'p' }
79
+
80
+ @sample.a_method('p').should eq 'hello'
81
+ end
82
+
83
+ it "should take an array of methods to provision" do
84
+ @sample.stub(:b_method).and_return('hello')
85
+ @meta.provision :a_method, :b_method, :with => lambda{ false }
86
+
87
+ @sample.a_method.should_not eq 'hello'
88
+ @sample.b_method.should_not eq 'hello'
89
+ end
90
+
91
+ it "should take a block as an action when provision fails" do
92
+ @meta.provision :a_method, :with => lambda{ false } do
93
+ 'hi there'
94
+ end
95
+
96
+ @sample.a_method.should eq 'hi there'
97
+ end
98
+
99
+ end
@@ -0,0 +1 @@
1
+ require 'provision'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: provision
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chen Fisher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
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
+ description: Lets one hook a provision for a method
31
+ email:
32
+ - chen.fisher@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - CHANGELOG.md
40
+ - Gemfile
41
+ - LICENSE.txt
42
+ - README.md
43
+ - Rakefile
44
+ - lib/provision.rb
45
+ - lib/provision/version.rb
46
+ - provision.gemspec
47
+ - spec/provision/sample.rb
48
+ - spec/provision_spec.rb
49
+ - spec/spec_helper.rb
50
+ homepage: https://github.com/chenfisher/provision
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.24
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: When a method is provisioned, any call to that method is passed through a
74
+ provision filter that can stop the method execution and perform some actions
75
+ test_files:
76
+ - spec/provision/sample.rb
77
+ - spec/provision_spec.rb
78
+ - spec/spec_helper.rb