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