draper 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,103 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.7.2
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ relpath = '';
19
+ if (relpath != '') relpath += '/';
20
+ </script>
21
+
22
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
25
+
26
+
27
+ </head>
28
+ <body>
29
+ <script type="text/javascript" charset="utf-8">
30
+ if (window.top.frames.main) document.body.className = 'frames';
31
+ </script>
32
+
33
+ <div id="header">
34
+ <div id="menu">
35
+
36
+ <a href="_index.html">Index</a> &raquo;
37
+
38
+
39
+ <span class="title">Top Level Namespace</span>
40
+
41
+
42
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
43
+ </div>
44
+
45
+ <div id="search">
46
+
47
+ <a id="class_list_link" href="#">Class List</a>
48
+
49
+ <a id="method_list_link" href="#">Method List</a>
50
+
51
+ <a id="file_list_link" href="#">File List</a>
52
+
53
+ </div>
54
+ <div class="clear"></div>
55
+ </div>
56
+
57
+ <iframe id="search_frame"></iframe>
58
+
59
+ <div id="content"><h1>Top Level Namespace
60
+
61
+
62
+
63
+ </h1>
64
+
65
+ <dl class="box">
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+ </dl>
75
+ <div class="clear"></div>
76
+
77
+ <h2>Defined Under Namespace</h2>
78
+ <p class="children">
79
+
80
+
81
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="Draper.html" title="Draper (module)">Draper</a></span>
82
+
83
+
84
+
85
+
86
+ </p>
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+ </div>
95
+
96
+ <div id="footer">
97
+ Generated on Thu Sep 1 01:13:37 2011 by
98
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
99
+ 0.7.2 (ruby-1.8.7).
100
+ </div>
101
+
102
+ </body>
103
+ </html>
@@ -6,72 +6,157 @@ module Draper
6
6
 
7
7
  DEFAULT_DENIED = Object.new.methods << :method_missing
8
8
  FORCED_PROXY = [:to_param]
9
+ FORCED_PROXY.each do |method|
10
+ define_method method do |*args, &block|
11
+ model.send method, *args, &block
12
+ end
13
+ end
9
14
  self.denied = DEFAULT_DENIED
10
15
 
11
- def initialize(input, context = nil)
16
+ # Initialize a new decorator instance by passing in
17
+ # an instance of the source class. Pass in an optional
18
+ # context is stored for later use.
19
+ #
20
+ # @param [Object] instance to wrap
21
+ # @param [Object] context (optional)
22
+ def initialize(input, context = {})
23
+ input.inspect # forces evaluation of a lazy query from AR
12
24
  input.inspect
13
25
  self.class.model_class = input.class if model_class.nil?
14
26
  @model = input
15
27
  self.context = context
16
- build_methods
17
28
  end
18
29
 
19
- def self.find(input)
20
- self.new(model_class.find(input))
30
+ # Proxies to the class specified by `decorates` to automatically
31
+ # lookup an object in the database and decorate it.
32
+ #
33
+ # @param [Symbol or String] id to lookup
34
+ # @return [Object] instance of this decorator class
35
+ def self.find(input, context = {})
36
+ self.new(model_class.find(input), context)
21
37
  end
22
38
 
39
+ # Typically called within a decorator definition, this method
40
+ # specifies the name of the wrapped object class.
41
+ #
42
+ # For instance, a `ProductDecorator` class might call `decorates :product`
43
+ #
44
+ # But they don't have to match in name, so a `EmployeeDecorator`
45
+ # class could call `decorates :person` to wrap instances of `Person`
46
+ #
47
+ # This is primarilly set so the `.find` method knows which class
48
+ # to query.
49
+ #
50
+ # @param [Symbol] class_name snakecase name of the decorated class, like `:product`
23
51
  def self.decorates(input)
24
52
  self.model_class = input.to_s.camelize.constantize
25
53
  model_class.send :include, Draper::ModelSupport
26
54
  end
27
55
 
56
+ # Specifies a black list of methods which may *not* be proxied to
57
+ # to the wrapped object.
58
+ #
59
+ # Do not use both `.allows` and `.denies` together, either write
60
+ # a whitelist with `.allows` or a blacklist with `.denies`
61
+ #
62
+ # @param [Symbols*] methods to deny like `:find, :find_by_name`
28
63
  def self.denies(*input_denied)
29
64
  raise ArgumentError, "Specify at least one method (as a symbol) to exclude when using denies" if input_denied.empty?
30
65
  raise ArgumentError, "Use either 'allows' or 'denies', but not both." if self.allowed?
31
66
  self.denied += input_denied
32
67
  end
33
68
 
69
+ # Specifies a white list of methods which *may* be proxied to
70
+ # to the wrapped object. When `allows` is used, only the listed
71
+ # methods and methods defined in the decorator itself will be
72
+ # available.
73
+ #
74
+ # Do not use both `.allows` and `.denies` together, either write
75
+ # a whitelist with `.allows` or a blacklist with `.denies`
76
+ #
77
+ # @param [Symbols*] methods to allow like `:find, :find_by_name`
34
78
  def self.allows(*input_allows)
35
79
  raise ArgumentError, "Specify at least one method (as a symbol) to allow when using allows" if input_allows.empty?
36
80
  raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.denied == DEFAULT_DENIED)
37
81
  self.allowed = input_allows
38
82
  end
39
83
 
40
- def self.decorate(input, context = nil)
84
+ # Initialize a new decorator instance by passing in
85
+ # an instance of the source class. Pass in an optional
86
+ # context is stored for later use.
87
+ #
88
+ # When passing in a single object, using `.decorate` is
89
+ # identical to calling `.new`. However, `.decorate` can
90
+ # also accept a collection and return a collection of
91
+ # individually decorated objects.
92
+ #
93
+ # @param [Object] instance(s) to wrap
94
+ # @param [Object] context (optional)
95
+ def self.decorate(input, context = {})
41
96
  input.respond_to?(:each) ? input.map{|i| new(i, context)} : new(input, context)
42
97
  end
43
98
 
99
+ # Access the helpers proxy to call built-in and user-defined
100
+ # Rails helpers. Aliased to `.h` for convinience.
101
+ #
102
+ # @return [Object] proxy
44
103
  def helpers
45
104
  @helpers ||= ApplicationController::all_helpers
46
105
  end
47
106
  alias :h :helpers
48
107
 
108
+ # Calling `lazy_helpers` will make the built-in and
109
+ # user-defined Rails helpers accessible as class methods
110
+ # in the decorator without using the `h.` or `helpers.` proxy.
111
+ #
112
+ # The drawback is that you dump many methods into your decorator's
113
+ # namespace and collisions could create unexpected results.
49
114
  def self.lazy_helpers
50
115
  self.send(:include, Draper::LazyHelpers)
51
116
  end
52
117
 
118
+ # Use primarily by `form_for`, this returns an instance of
119
+ # `ActiveModel::Name` set to the wrapped model's class name
120
+ #
121
+ # @return [ActiveModel::Name] model_name
53
122
  def self.model_name
54
123
  ActiveModel::Name.new(model_class)
55
124
  end
56
125
 
126
+ # Fetch the original wrapped model.
127
+ #
128
+ # @return [Object] original_model
57
129
  def to_model
58
130
  @model
59
131
  end
60
132
 
133
+ # Delegates == to the decorated models
134
+ #
135
+ # @return [Boolean] true if other's model == self's model
136
+ def ==(other)
137
+ @model == other.model
138
+ end
139
+
140
+ def respond_to?(method)
141
+ if select_methods.include?(method)
142
+ model.respond_to?(method)
143
+ else
144
+ super
145
+ end
146
+ end
147
+
148
+ def method_missing(method, *args, &block)
149
+ if select_methods.include?(method)
150
+ model.send(method, *args, &block)
151
+ else
152
+ super
153
+ end
154
+ end
155
+
61
156
  private
62
157
  def select_methods
63
158
  specified = self.allowed || (model.public_methods.map{|s| s.to_sym} - denied.map{|s| s.to_sym})
64
159
  (specified - self.public_methods.map{|s| s.to_sym}) + FORCED_PROXY
65
160
  end
66
-
67
- def build_methods
68
- select_methods.each do |method|
69
- (class << self; self; end).class_eval do
70
- define_method method do |*args, &block|
71
- model.send method, *args, &block
72
- end
73
- end
74
- end
75
- end
76
161
  end
77
162
  end
@@ -1,5 +1,6 @@
1
1
  module Draper::ModelSupport
2
2
  def decorator
3
3
  @decorator ||= "#{self.class.name}Decorator".constantize.decorate(self)
4
+ block_given? ? yield(@decorator) : @decorator
4
5
  end
5
6
  end
@@ -1,3 +1,3 @@
1
1
  module Draper
2
- VERSION = "0.7.3"
2
+ VERSION = "0.7.4"
3
3
  end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../../draper/decorator/decorator_generator.rb', __FILE__)
2
+ class Rails::DecoratorGenerator < Draper::DecoratorGenerator
3
+
4
+ source_root File.expand_path('../../draper/decorator/templates', __FILE__)
5
+
6
+ class_option :invoke_after_finished, :type => :string, :description => "Generator to invoke when finished"
7
+
8
+ def build_model_and_application_decorators
9
+ super
10
+ if self.options[:invoke_after_finished]
11
+ Rails::Generators.invoke(self.options[:invoke_after_finished], [@name, @_initializer.first[1..-1]])
12
+ end
13
+ end
14
+
15
+ end
@@ -43,8 +43,9 @@ describe Draper::Base do
43
43
 
44
44
  context("selecting methods") do
45
45
  it "echos the methods of the wrapped class except default exclusions" do
46
+ pending "Fine on 1.9 but fails on 1.8 due to differences in implementation of respond_to and method_missing. Help?"
46
47
  source.methods.each do |method|
47
- unless Draper::Base::DEFAULT_DENIED.include?(method)
48
+ unless Draper::Base::DEFAULT_DENIED.include?(method)
48
49
  subject.should respond_to(method)
49
50
  end
50
51
  end
@@ -88,6 +89,11 @@ describe Draper::Base do
88
89
  pd.should be_instance_of(ProductDecorator)
89
90
  pd.model.should be_instance_of(Product)
90
91
  end
92
+
93
+ it "should accept and store a context" do
94
+ pd = ProductDecorator.find(1, :admin)
95
+ pd.context.should == :admin
96
+ end
91
97
  end
92
98
 
93
99
  context ".decorate" do
@@ -132,6 +138,13 @@ describe Draper::Base do
132
138
  end
133
139
  end
134
140
 
141
+ context('.==') do
142
+ it "should compare the decorated models" do
143
+ other = Draper::Base.new(source)
144
+ subject.should == other
145
+ end
146
+ end
147
+
135
148
  describe "a sample usage with denies" do
136
149
  let(:subject_with_denies){ DecoratorWithDenies.new(source) }
137
150
 
@@ -156,11 +169,11 @@ describe Draper::Base do
156
169
  let(:subject_with_allows){ DecoratorWithAllows.new(source) }
157
170
 
158
171
  it "should echo the allowed method" do
159
- subject_with_allows.should respond_to(:upcase)
172
+ subject_with_allows.should respond_to(:goodnight_moon)
160
173
  end
161
174
 
162
175
  it "should echo _only_ the allowed method" do
163
- subject_with_allows.should_not respond_to(:downcase)
176
+ subject_with_allows.should_not respond_to(:hello_world)
164
177
  end
165
178
  end
166
179
 
@@ -6,5 +6,10 @@ describe Draper::ModelSupport do
6
6
  describe '#decorator' do
7
7
  its(:decorator) { should be_kind_of(ProductDecorator) }
8
8
  its(:decorator) { should be(subject.decorator) }
9
+
10
+ it 'should have abillity to pass block' do
11
+ a = Product.new.decorator { |d| d.awesome_title }
12
+ a.should eql "Awesome Title"
13
+ end
9
14
  end
10
15
  end
@@ -1,7 +1,4 @@
1
1
  module ActiveRecord
2
2
  class Base
3
- def method_missing(name, *args)
4
- name
5
- end
6
3
  end
7
- end
4
+ end
@@ -1,3 +1,3 @@
1
1
  class DecoratorWithAllows < Draper::Base
2
- allows :upcase
2
+ allows :goodnight_moon
3
3
  end
@@ -1,3 +1,7 @@
1
1
  class ProductDecorator < Draper::Base
2
2
  decorates :product
3
+
4
+ def awesome_title
5
+ "Awesome Title"
6
+ end
3
7
  end
metadata CHANGED
@@ -1,39 +1,52 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: draper
3
- version: !ruby/object:Gem::Version
4
- hash: 5
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.4
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 7
9
- - 3
10
- version: 0.7.3
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Jeff Casimir
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-08-29 00:00:00 Z
12
+ date: 2011-10-03 00:00:00.000000000Z
19
13
  dependencies: []
20
-
21
- description: Draper reimagines the role of helpers in the view layer of a Rails application, allowing an object-oriented approach rather than procedural.
22
- email:
14
+ description: Draper reimagines the role of helpers in the view layer of a Rails application,
15
+ allowing an object-oriented approach rather than procedural.
16
+ email:
23
17
  - jeff@casimircreative.com
24
18
  executables: []
25
-
26
19
  extensions: []
27
-
28
20
  extra_rdoc_files: []
29
-
30
- files:
21
+ files:
31
22
  - .gitignore
32
23
  - .travis.yml
24
+ - .yardopts
33
25
  - Gemfile
34
26
  - Guardfile
35
27
  - Rakefile
36
28
  - Readme.markdown
29
+ - doc/ApplicationDecorator.html
30
+ - doc/Draper.html
31
+ - doc/Draper/AllHelpers.html
32
+ - doc/Draper/Base.html
33
+ - doc/Draper/DecoratorGenerator.html
34
+ - doc/Draper/LazyHelpers.html
35
+ - doc/Draper/ModelSupport.html
36
+ - doc/Draper/System.html
37
+ - doc/_index.html
38
+ - doc/class_list.html
39
+ - doc/css/common.css
40
+ - doc/css/full_list.css
41
+ - doc/css/style.css
42
+ - doc/file_list.html
43
+ - doc/frames.html
44
+ - doc/index.html
45
+ - doc/js/app.js
46
+ - doc/js/full_list.js
47
+ - doc/js/jquery.js
48
+ - doc/method_list.html
49
+ - doc/top-level-namespace.html
37
50
  - draper.gemspec
38
51
  - lib/draper.rb
39
52
  - lib/draper/all_helpers.rb
@@ -46,6 +59,7 @@ files:
46
59
  - lib/generators/draper/decorator/decorator_generator.rb
47
60
  - lib/generators/draper/decorator/templates/application_decorator.rb
48
61
  - lib/generators/draper/decorator/templates/decorator.rb
62
+ - lib/generators/rails/decorator_generator.rb
49
63
  - spec/base_spec.rb
50
64
  - spec/draper/model_support_spec.rb
51
65
  - spec/samples/active_record.rb
@@ -59,38 +73,29 @@ files:
59
73
  - spec/spec_helper.rb
60
74
  homepage: http://github.com/jcasimir/draper
61
75
  licenses: []
62
-
63
76
  post_install_message:
64
77
  rdoc_options: []
65
-
66
- require_paths:
78
+ require_paths:
67
79
  - lib
68
- required_ruby_version: !ruby/object:Gem::Requirement
80
+ required_ruby_version: !ruby/object:Gem::Requirement
69
81
  none: false
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- hash: 3
74
- segments:
75
- - 0
76
- version: "0"
77
- required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
87
  none: false
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- hash: 3
83
- segments:
84
- - 0
85
- version: "0"
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
86
92
  requirements: []
87
-
88
93
  rubyforge_project: draper
89
- rubygems_version: 1.8.6
94
+ rubygems_version: 1.8.10
90
95
  signing_key:
91
96
  specification_version: 3
92
97
  summary: Decorator pattern implmentation for Rails.
93
- test_files:
98
+ test_files:
94
99
  - spec/base_spec.rb
95
100
  - spec/draper/model_support_spec.rb
96
101
  - spec/samples/active_record.rb