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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode
5
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rake'
4
+ gem 'activesupport'
5
+
6
+ # Specify your gem's dependencies in artdeco.gemspec
7
+ gemspec
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
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+
6
+ task default: [:test]
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.pattern = "test/*.rb"
10
+ end
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
@@ -0,0 +1,3 @@
1
+ module Artdeco
2
+ VERSION = "1.1.0"
3
+ 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: []