concern 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ task :default => :spec
2
+ require 'spec/rake/spectask'
3
+ Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color']}
4
+
5
+ begin
6
+ require 'jeweler'
7
+ project_name = 'concern'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = project_name
10
+ gem.description = gem.summary = "Seperation of concerns without meta-madness and namespace pollution"
11
+ gem.email = "grosser.michael@gmail.com"
12
+ gem.homepage = "http://github.com/grosser/#{project_name}"
13
+ gem.authors = ["Michael Grosser"]
14
+ end
15
+
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
@@ -0,0 +1,74 @@
1
+ Seperation of concerns with clean namespaces.
2
+
3
+ Normal includes and extensions pollute the namespace and share private/protected.
4
+ With concern, everything stays in the Concern, can access the concerned and keep namespaced+private.
5
+
6
+ Install
7
+ =======
8
+ - As Rails plugin: `rails plugin install git://github.com/grosser/concern.git `
9
+ - As gem: ` gem install concern `
10
+
11
+ Usage
12
+ =====
13
+ Simple:
14
+ # a.rb
15
+ require 'concern'
16
+ class A
17
+ concern 'a/acl'
18
+
19
+ def admin? ...
20
+ end
21
+
22
+ # a/acl.rb
23
+ # can access concerned methods like `admin?`
24
+ class A::ACL < Concern
25
+ def can_access?(vault)
26
+ admin? and secret
27
+ end
28
+
29
+ private
30
+
31
+ def secrect ...
32
+ end
33
+
34
+ A.new.acl.can_access?(BankAccount)
35
+
36
+ Let no outsider know, and use delegate:
37
+
38
+ class A
39
+ class Messages
40
+ def write ...
41
+ def read ...
42
+ end
43
+
44
+ concern 'a/acl', :delegate => true # delegate all public methods
45
+ concern 'a/messages', :delegate => [:write]
46
+ end
47
+
48
+ A.new.can_access?(BankAccount) # no more `.acl` needed
49
+ A.new.write
50
+ A.new.messages.read
51
+
52
+ Adding to the concerned, e.g. validations/associations/scopes etc.
53
+ class User < ActiveRecord::Base
54
+ concern 'user/validator', :delegate => true
55
+ end
56
+
57
+ # user/validator.rb
58
+ class User::Validator < Concern
59
+ def self.included(concerned)
60
+ concerned.class_eval do
61
+ validates_presence_of :name, :if => :name_seems_legit?
62
+ end
63
+ end
64
+
65
+ def name_seems_legit? ..
66
+ end
67
+
68
+ More examples can be found in [spec/examples](http://github.com/grosser/concern/tree/master/spec/examples)
69
+
70
+ Author
71
+ ======
72
+ [Michael Grosser](http://grosser.it)
73
+ grosser.michael@gmail.com
74
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile.rb, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{concern}
8
+ s.version = "0.2.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2010-10-19}
13
+ s.description = %q{Seperation of concerns without meta-madness and namespace pollution}
14
+ s.email = %q{grosser.michael@gmail.com}
15
+ s.files = [
16
+ "Rakefile.rb",
17
+ "Readme.md",
18
+ "VERSION",
19
+ "concern.gemspec",
20
+ "init.rb",
21
+ "lib/concern.rb",
22
+ "spec/concern_spec.rb",
23
+ "spec/examples/a/b.rb",
24
+ "spec/examples/a/bc_def_gh.rb",
25
+ "spec/examples/adding.rb",
26
+ "spec/examples/complex_inline.rb",
27
+ "spec/examples/complex_require.rb",
28
+ "spec/examples/delegate.rb",
29
+ "spec/examples/inline.rb",
30
+ "spec/examples/load.rb",
31
+ "spec/examples/parent_warning.rb",
32
+ "spec/examples/picky_delegate.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/grosser/concern}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.6}
38
+ s.summary = %q{Seperation of concerns without meta-madness and namespace pollution}
39
+ s.test_files = [
40
+ "spec/concern_spec.rb",
41
+ "spec/examples/picky_delegate.rb",
42
+ "spec/examples/complex_inline.rb",
43
+ "spec/examples/parent_warning.rb",
44
+ "spec/examples/adding.rb",
45
+ "spec/examples/complex_require.rb",
46
+ "spec/examples/load.rb",
47
+ "spec/examples/a/b.rb",
48
+ "spec/examples/a/bc_def_gh.rb",
49
+ "spec/examples/delegate.rb",
50
+ "spec/examples/inline.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ else
59
+ end
60
+ else
61
+ end
62
+ end
63
+
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ #only needed wen used as Rails plugin
2
+ require 'concern'
@@ -0,0 +1,59 @@
1
+ class Concern
2
+ VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
3
+
4
+ attr_accessor :concerned
5
+
6
+ def self.classify(lib)
7
+ lib.split('/').map{|part| part.gsub(/(?:^|_)(.)/){ $1.upcase } }.join('::')
8
+ end
9
+ end
10
+
11
+ class Object
12
+ def self.concern(lib, options={})
13
+ # load delegate
14
+ lib = lib.to_s
15
+ klass = Concern.classify(lib)
16
+ begin
17
+ klass = eval(klass)
18
+ rescue
19
+ require lib
20
+ klass = eval(klass)
21
+ end
22
+
23
+ unless klass.instance_methods.map{|x|x.to_s}.include?('concerned=')
24
+ raise "A concern must always extend Concern"
25
+ end
26
+
27
+ # make accessor
28
+ accessor = lib.split('/').last.to_sym
29
+ eval <<-EOF
30
+ def #{accessor}
31
+ return @#{accessor} if @#{accessor}
32
+ @#{accessor} = #{klass}.new
33
+ @#{accessor}.concerned = self
34
+ @#{accessor}
35
+ end
36
+ EOF
37
+
38
+ # call included
39
+ base = eval(name) #self.class is always Class, but name is class that called concern
40
+ klass.included(base) if klass.respond_to? :included
41
+
42
+ # delegate methods
43
+ if options[:delegate]
44
+ methods = if options[:delegate].is_a?(Array)
45
+ options[:delegate]
46
+ else
47
+ klass.public_instance_methods(false)
48
+ end
49
+
50
+ methods.each do |method|
51
+ eval <<-EOF
52
+ def #{method}(*args)
53
+ #{accessor}.#{method}(*args)
54
+ end
55
+ EOF
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ describe "Concern" do
2
+ it "loads a simple file" do
3
+ `ruby spec/examples/load.rb`.should == "hello"
4
+ end
5
+
6
+ it "requires a complex file" do
7
+ `ruby spec/examples/complex_require.rb`.should == "SUCCESS"
8
+ end
9
+
10
+ it "can use already present class" do
11
+ `ruby spec/examples/inline.rb`.should == "inline"
12
+ end
13
+
14
+ it "can use complex present class" do
15
+ `ruby spec/examples/complex_inline.rb`.should == "SUCCESS"
16
+ end
17
+
18
+ it "can delegate" do
19
+ `ruby spec/examples/delegate.rb`.should == "hello"
20
+ end
21
+
22
+ it "can delegate some" do
23
+ `ruby spec/examples/picky_delegate.rb`.should == "hello"
24
+ end
25
+
26
+ it "add to parent" do
27
+ `ruby spec/examples/adding.rb`.should == "yepworld"
28
+ end
29
+
30
+ it "warns when parent is not Concern" do
31
+ `ruby spec/examples/parent_warning.rb`.should == "SUCCESS"
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ class A::B < Concern
2
+ def test
3
+ 'hello'
4
+ end
5
+
6
+ def test2
7
+ 'ohoh'
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class A::BcDefGh < Concern
2
+ def test
3
+ 'SUCCESS'
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ class B < Concern
6
+ def initialize
7
+ super
8
+ @hello = 'world'
9
+ end
10
+
11
+ def hello
12
+ @hello
13
+ end
14
+
15
+ def self.included(base)
16
+ base.class_eval do
17
+ test
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.test
23
+ print "yep"
24
+ end
25
+
26
+ concern 'a/b'
27
+ end
28
+
29
+ print A.new.b.hello
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ module Bc
6
+ class DefGh < Concern
7
+ def test
8
+ 'SUCCESS'
9
+ end
10
+ end
11
+ end
12
+ concern 'a/bc/def_gh', :delegate=>true
13
+ end
14
+
15
+ print A.new.test
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ concern 'a/bc_def_gh', :delegate=>true
6
+ end
7
+
8
+ print A.new.test
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ def xxx
6
+ 'xxx'
7
+ end
8
+ concern 'a/b', :delegate=>true
9
+ end
10
+
11
+ raise if A.new.send(:xxx) != 'xxx'
12
+ print A.new.test
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH << 'lib'
2
+ require 'concern'
3
+
4
+ class A
5
+ class B < Concern
6
+ def test
7
+ 'inline'
8
+ end
9
+ end
10
+ concern 'a/b'
11
+ end
12
+
13
+ print A.new.b.test
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ concern 'a/b'
6
+ end
7
+
8
+ print A.new.b.test
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+
4
+ class A
5
+ class B # < Concern
6
+ end
7
+
8
+ begin
9
+ concern 'a/b'
10
+ print 'FAIL'
11
+ rescue
12
+ raise unless $!.to_s =~ /extend Concern/
13
+ print 'SUCCESS'
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH << 'lib' << 'spec/examples'
2
+ require 'concern'
3
+ class A
4
+ concern 'a/b', :delegate=>[:test]
5
+ end
6
+
7
+ ok = begin
8
+ A.new.test2
9
+ false
10
+ rescue
11
+ true
12
+ end
13
+ raise unless ok
14
+ print A.new.test
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: concern
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 1
9
+ version: 0.2.1
10
+ platform: ruby
11
+ authors:
12
+ - Michael Grosser
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-19 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Seperation of concerns without meta-madness and namespace pollution
22
+ email: grosser.michael@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Rakefile.rb
31
+ - Readme.md
32
+ - VERSION
33
+ - concern.gemspec
34
+ - init.rb
35
+ - lib/concern.rb
36
+ - spec/concern_spec.rb
37
+ - spec/examples/a/b.rb
38
+ - spec/examples/a/bc_def_gh.rb
39
+ - spec/examples/adding.rb
40
+ - spec/examples/complex_inline.rb
41
+ - spec/examples/complex_require.rb
42
+ - spec/examples/delegate.rb
43
+ - spec/examples/inline.rb
44
+ - spec/examples/load.rb
45
+ - spec/examples/parent_warning.rb
46
+ - spec/examples/picky_delegate.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/grosser/concern
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.6
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Seperation of concerns without meta-madness and namespace pollution
77
+ test_files:
78
+ - spec/concern_spec.rb
79
+ - spec/examples/picky_delegate.rb
80
+ - spec/examples/complex_inline.rb
81
+ - spec/examples/parent_warning.rb
82
+ - spec/examples/adding.rb
83
+ - spec/examples/complex_require.rb
84
+ - spec/examples/load.rb
85
+ - spec/examples/a/b.rb
86
+ - spec/examples/a/bc_def_gh.rb
87
+ - spec/examples/delegate.rb
88
+ - spec/examples/inline.rb