artdeco 1.1.0
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 +4 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/README.md +57 -0
- data/Rakefile +10 -0
- data/artdeco.gemspec +24 -0
- data/lib/artdeco/version.rb +3 -0
- data/lib/artdeco.rb +81 -0
- data/test/artdeco_test.rb +127 -0
- metadata +54 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Artdeco
|
2
|
+
|
3
|
+
[![Build History][2]][1]
|
4
|
+
|
5
|
+
[1]: http://travis-ci.org/tracksun/artdeco
|
6
|
+
[2]: https://secure.travis-ci.org/tracksun/artdeco.png?branch=master
|
7
|
+
|
8
|
+
Decorators for Rails
|
9
|
+
|
10
|
+
* extend an object with given classes (default is \<object.class\>Decorator, if defined)
|
11
|
+
* make helpers accessible in object via :h
|
12
|
+
|
13
|
+
### Example
|
14
|
+
|
15
|
+
Decorate a model in your controller:
|
16
|
+
|
17
|
+
def show
|
18
|
+
article = Article.find(params[:id])
|
19
|
+
@article = Artdeco.decorate(article, self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def index
|
23
|
+
articles = Article.all
|
24
|
+
@articles = Artdeco.decorate(articles, self)
|
25
|
+
end
|
26
|
+
|
27
|
+
Then @article will be extended by module ArticleDecorator
|
28
|
+
and has access to your helpers via :h
|
29
|
+
|
30
|
+
module ArticleDecorator
|
31
|
+
def image
|
32
|
+
h.image_tag('article')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
and your views may use the decorated model:
|
37
|
+
|
38
|
+
# app/views/articles/show.html.haml
|
39
|
+
%h1
|
40
|
+
Article
|
41
|
+
= @article.image
|
42
|
+
|
43
|
+
|
44
|
+
Modules for decoration may be given explicitly:
|
45
|
+
|
46
|
+
Artdeco.decorate(user, self, decorator: Customer)
|
47
|
+
|
48
|
+
# or
|
49
|
+
|
50
|
+
Artdeco.decorate(user, self, decorator: [ Customer, Admin ] )
|
51
|
+
|
52
|
+
|
53
|
+
For conveniance decorated objects may decorate other objects:
|
54
|
+
|
55
|
+
Artdeco.decorate(order, self)
|
56
|
+
|
57
|
+
order.decorate(shopping_card)
|
data/Rakefile
ADDED
data/artdeco.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "artdeco/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "artdeco"
|
7
|
+
s.version = Artdeco::VERSION
|
8
|
+
s.authors = ["Thomas Sonntag"]
|
9
|
+
s.email = ["git@sonntagsbox.de"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Decorators for Rails}
|
12
|
+
s.description = %q{Decorate models with views in a object oriented way}
|
13
|
+
|
14
|
+
s.rubyforge_project = "artdeco"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
data/lib/artdeco.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'active_support/core_ext/array/extract_options'
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
|
5
|
+
module Artdeco
|
6
|
+
|
7
|
+
module DecoratorMethods
|
8
|
+
|
9
|
+
def decorate model, *decorator_classes
|
10
|
+
return nil if model.nil?
|
11
|
+
decorator_classes = @decorator_classes || default_decorator_class(model) if decorator_classes.empty?
|
12
|
+
[decorator_classes].flatten.each{|dc|model.extend dc}
|
13
|
+
h = self.h
|
14
|
+
model.define_singleton_method(:h){h}
|
15
|
+
model.extend DecoratorMethods
|
16
|
+
model
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def default_decorator_class model
|
21
|
+
@_decorator_classes_cache ||= {}
|
22
|
+
[@_decorator_classes_cache.fetch(model.class){"::#{model.class}Decorator".constantize rescue nil}].compact
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def decorate model, *args
|
29
|
+
Decorator.new(*args).decorate(model)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Decorator
|
34
|
+
|
35
|
+
include DecoratorMethods
|
36
|
+
|
37
|
+
attr_reader :params, :view_context
|
38
|
+
alias_method :h, :view_context
|
39
|
+
|
40
|
+
# Args may be either the params hash of the request
|
41
|
+
# or an object which responds to :params and optionally to :view_context, e.g. a controller instance
|
42
|
+
# If a view_context is given it will be accessible in various blocks by calling :h
|
43
|
+
def initialize *args
|
44
|
+
opts = args.extract_options!
|
45
|
+
|
46
|
+
@decorator_classes = ([opts.delete(:decorators)] + [opts.delete(:decorator)]).flatten.compact
|
47
|
+
@decorator_classes = nil if @decorator_classes.empty? # required for #decorate
|
48
|
+
|
49
|
+
case args.size
|
50
|
+
when 0
|
51
|
+
@view_context = opts.delete :view_context
|
52
|
+
@params = opts.delete(:params){opts}
|
53
|
+
when 1
|
54
|
+
arg = args.first
|
55
|
+
@view_context = arg.respond_to?(:view_context) ? arg.view_context : nil
|
56
|
+
|
57
|
+
if arg.respond_to? :params
|
58
|
+
@params = arg.params.symbolize_keys.merge(opts)
|
59
|
+
else
|
60
|
+
raise ArgumentError, 'argument must respond_to :params'
|
61
|
+
end
|
62
|
+
else
|
63
|
+
raise ArgumentError, 'too many arguments' if args.size > 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# evaluate data (string or proc)
|
68
|
+
# if model is provided it will accessible in evaluated data
|
69
|
+
def eval data, model = nil
|
70
|
+
case data
|
71
|
+
when Proc
|
72
|
+
(model ? model : self).instance_exec(&data)
|
73
|
+
else
|
74
|
+
data
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
self.extend ClassMethods
|
81
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$:.unshift File.expand_path( '../lib/', File.dirname( __FILE__))
|
3
|
+
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'artdeco'
|
6
|
+
|
7
|
+
class ArtdecoTest < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
class Foo
|
10
|
+
def foo
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class FooHelper
|
15
|
+
def hi
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module FooDecorator
|
20
|
+
def ho
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module BlaDecorator
|
25
|
+
def bla
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class FakeController
|
30
|
+
|
31
|
+
def view_context
|
32
|
+
@view_context ||= FooHelper.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def params
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing *args
|
40
|
+
view_content.send *args
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_decorate_model
|
45
|
+
model = Foo.new
|
46
|
+
controller = FakeController.new
|
47
|
+
Artdeco.decorate model, controller
|
48
|
+
|
49
|
+
assert_respond_to model, :h
|
50
|
+
assert_respond_to model, :ho
|
51
|
+
assert_respond_to model, :decorate
|
52
|
+
|
53
|
+
h = model.h
|
54
|
+
assert_equal FooHelper, h.class
|
55
|
+
assert_respond_to h, :hi
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_decorate_model_with_given_decorator
|
59
|
+
model = Foo.new
|
60
|
+
controller = FakeController.new
|
61
|
+
Artdeco.decorate model, controller, decorators: BlaDecorator
|
62
|
+
|
63
|
+
assert_respond_to model, :h
|
64
|
+
assert_respond_to model, :bla
|
65
|
+
assert_respond_to model, :decorate
|
66
|
+
|
67
|
+
h = model.h
|
68
|
+
assert_equal FooHelper, h.class
|
69
|
+
assert_respond_to h, :hi
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_decorate_model_with_given_decorators
|
73
|
+
model = Foo.new
|
74
|
+
controller = FakeController.new
|
75
|
+
Artdeco.decorate model, controller, decorators: [BlaDecorator, FooDecorator]
|
76
|
+
|
77
|
+
assert_respond_to model, :h
|
78
|
+
assert_respond_to model, :ho
|
79
|
+
assert_respond_to model, :bla
|
80
|
+
assert_respond_to model, :decorate
|
81
|
+
|
82
|
+
h = model.h
|
83
|
+
assert_equal FooHelper, h.class
|
84
|
+
assert_respond_to h, :hi
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_decorated_model_can_decorate
|
88
|
+
model = Foo.new
|
89
|
+
controller = FakeController.new
|
90
|
+
model = Artdeco.decorate model, controller
|
91
|
+
|
92
|
+
other = Foo.new
|
93
|
+
model.decorate other
|
94
|
+
|
95
|
+
assert_respond_to other, :h
|
96
|
+
assert_respond_to other, :ho
|
97
|
+
assert_respond_to other, :decorate
|
98
|
+
|
99
|
+
h = other.h
|
100
|
+
assert_equal FooHelper, h.class
|
101
|
+
|
102
|
+
|
103
|
+
another = Foo.new
|
104
|
+
model.decorate another, BlaDecorator
|
105
|
+
|
106
|
+
assert_respond_to another, :h
|
107
|
+
assert_respond_to another, :bla
|
108
|
+
assert !another.respond_to?(:ho)
|
109
|
+
assert_respond_to another, :decorate
|
110
|
+
|
111
|
+
h = another.h
|
112
|
+
assert_equal FooHelper, h.class
|
113
|
+
end
|
114
|
+
|
115
|
+
def decorator_with_hash_argument
|
116
|
+
model = Foo.new
|
117
|
+
Artdeco.decorate model, view_context: FooHelper.new, params: {}
|
118
|
+
|
119
|
+
assert_respond_to model, :h
|
120
|
+
assert_respond_to model, :ho
|
121
|
+
assert_respond_to model, :decorate
|
122
|
+
|
123
|
+
h = model.h
|
124
|
+
assert_equal FooHelper, h.class
|
125
|
+
assert_respond_to h, :hi
|
126
|
+
end
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: artdeco
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Sonntag
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Decorate models with views in a object oriented way
|
15
|
+
email:
|
16
|
+
- git@sonntagsbox.de
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- .travis.yml
|
23
|
+
- Gemfile
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- artdeco.gemspec
|
27
|
+
- lib/artdeco.rb
|
28
|
+
- lib/artdeco/version.rb
|
29
|
+
- test/artdeco_test.rb
|
30
|
+
homepage: ''
|
31
|
+
licenses: []
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project: artdeco
|
50
|
+
rubygems_version: 1.8.11
|
51
|
+
signing_key:
|
52
|
+
specification_version: 3
|
53
|
+
summary: Decorators for Rails
|
54
|
+
test_files: []
|