keynote 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of keynote might be problematic. Click here for more details.
- data/.gitignore +19 -0
- data/.yardopts +4 -0
- data/Appraisals +20 -0
- data/Gemfile +4 -0
- data/LICENSE +27 -0
- data/README.md +8 -0
- data/Rakefile +17 -0
- data/keynote.gemspec +26 -0
- data/lib/generators/presenter_generator.rb +70 -0
- data/lib/generators/templates/keynote_mini_test_spec.rb +11 -0
- data/lib/generators/templates/keynote_mini_test_unit.rb +11 -0
- data/lib/generators/templates/keynote_presenter.rb +7 -0
- data/lib/generators/templates/keynote_rspec.rb +5 -0
- data/lib/generators/templates/keynote_test_unit.rb +11 -0
- data/lib/keynote.rb +65 -0
- data/lib/keynote/cache.rb +53 -0
- data/lib/keynote/controller.rb +14 -0
- data/lib/keynote/helper.rb +14 -0
- data/lib/keynote/presenter.rb +90 -0
- data/lib/keynote/railtie.rb +40 -0
- data/lib/keynote/rumble.rb +369 -0
- data/lib/keynote/testing/minitest_rails.rake +2 -0
- data/lib/keynote/testing/minitest_rails.rb +22 -0
- data/lib/keynote/testing/rspec.rb +16 -0
- data/lib/keynote/testing/test_unit.rb +6 -0
- data/lib/keynote/version.rb +6 -0
- data/spec/generator_spec.rb +106 -0
- data/spec/helper.rb +84 -0
- data/spec/keynote_spec.rb +98 -0
- data/spec/presenter_spec.rb +116 -0
- data/spec/railtie_spec.rb +32 -0
- data/spec/rumble_spec.rb +201 -0
- data/spec/test_case_spec.rb +12 -0
- metadata +204 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
require 'rails/generators'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
describe "generators" do
|
8
|
+
def invoke_generator(*args)
|
9
|
+
FileUtils.mkdir_p(output_path)
|
10
|
+
|
11
|
+
args.push '--quiet'
|
12
|
+
|
13
|
+
retval = Rails::Generators.invoke 'presenter', args,
|
14
|
+
:behavior => :invoke,
|
15
|
+
:destination_root => output_path
|
16
|
+
|
17
|
+
assert retval, 'Generator must succeed'
|
18
|
+
yield retval.drop(2)
|
19
|
+
ensure
|
20
|
+
FileUtils.rm_rf(output_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def output_path
|
24
|
+
File.expand_path('../../tmp', __FILE__)
|
25
|
+
end
|
26
|
+
|
27
|
+
def file_contents(path)
|
28
|
+
file_contents = File.read(File.join(output_path, path))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should generate a presenter and Test::Unit file" do
|
32
|
+
Rails.application.config.generators do |g|
|
33
|
+
g.test_framework :test_unit, :spec => true
|
34
|
+
end
|
35
|
+
|
36
|
+
invoke_generator 'post' do |files|
|
37
|
+
files.must_equal %w(
|
38
|
+
app/presenters/post_presenter.rb
|
39
|
+
test/unit/presenters/post_presenter_test.rb
|
40
|
+
)
|
41
|
+
|
42
|
+
file_contents('app/presenters/post_presenter.rb').
|
43
|
+
must_match /class PostPresenter < Keynote::Presenter/
|
44
|
+
|
45
|
+
file_contents('test/unit/presenters/post_presenter_test.rb').
|
46
|
+
must_match /class PostPresenterTest < Keynote::TestCase/
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should generate a presenter and RSpec file" do
|
51
|
+
Rails.application.config.generators do |g|
|
52
|
+
g.test_framework :rspec
|
53
|
+
end
|
54
|
+
|
55
|
+
invoke_generator 'post' do |files|
|
56
|
+
files.must_equal %w(
|
57
|
+
app/presenters/post_presenter.rb
|
58
|
+
spec/presenters/post_presenter_spec.rb
|
59
|
+
)
|
60
|
+
|
61
|
+
file_contents('app/presenters/post_presenter.rb').
|
62
|
+
must_match /class PostPresenter < Keynote::Presenter/
|
63
|
+
|
64
|
+
file_contents('spec/presenters/post_presenter_spec.rb').
|
65
|
+
must_match /describe PostPresenter do/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should generate a presenter and MiniTest::Rails spec file" do
|
70
|
+
Rails.application.config.generators do |g|
|
71
|
+
g.test_framework :mini_test, :spec => true
|
72
|
+
end
|
73
|
+
|
74
|
+
invoke_generator 'post' do |files|
|
75
|
+
files.must_equal %w(
|
76
|
+
app/presenters/post_presenter.rb
|
77
|
+
test/presenters/post_presenter_test.rb
|
78
|
+
)
|
79
|
+
|
80
|
+
file_contents('app/presenters/post_presenter.rb').
|
81
|
+
must_match /class PostPresenter < Keynote::Presenter/
|
82
|
+
|
83
|
+
file_contents('test/presenters/post_presenter_test.rb').
|
84
|
+
must_match /describe PostPresenter do/
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should generate a presenter and MiniTest::Rails unit file" do
|
89
|
+
Rails.application.config.generators do |g|
|
90
|
+
g.test_framework :mini_test, :spec => false
|
91
|
+
end
|
92
|
+
|
93
|
+
invoke_generator 'post' do |files|
|
94
|
+
files.must_equal %w(
|
95
|
+
app/presenters/post_presenter.rb
|
96
|
+
test/presenters/post_presenter_test.rb
|
97
|
+
)
|
98
|
+
|
99
|
+
file_contents('app/presenters/post_presenter.rb').
|
100
|
+
must_match /class PostPresenter < Keynote::Presenter/
|
101
|
+
|
102
|
+
file_contents('test/presenters/post_presenter_test.rb').
|
103
|
+
must_match /class PostPresenterTest < Keynote::MiniTest::TestCase/
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'minitest/spec'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'mocha'
|
6
|
+
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
require 'rails'
|
10
|
+
require 'action_controller/railtie'
|
11
|
+
require 'action_mailer/railtie'
|
12
|
+
require 'rails/test_unit/railtie'
|
13
|
+
|
14
|
+
require 'keynote'
|
15
|
+
|
16
|
+
## Initialize our test app (by Jose Valim: https://gist.github.com/1942658)
|
17
|
+
|
18
|
+
class TestApp < Rails::Application
|
19
|
+
config.active_support.deprecation = :log
|
20
|
+
config.eager_load = false
|
21
|
+
|
22
|
+
config.secret_token = 'a' * 100
|
23
|
+
end
|
24
|
+
|
25
|
+
class HelloController < ActionController::Base
|
26
|
+
def world
|
27
|
+
render :text => "Hello world!", :layout => false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
TestApp.initialize!
|
32
|
+
|
33
|
+
# We have to define this class because it's hard-coded into the definition of
|
34
|
+
# ActiveSupport::TestCase, which will load regardless of whether we load
|
35
|
+
# ActiveRecord.
|
36
|
+
module ActiveRecord
|
37
|
+
class Model
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
## Examples
|
42
|
+
|
43
|
+
class EmptyPresenter < Keynote::Presenter
|
44
|
+
end
|
45
|
+
|
46
|
+
class NormalPresenter < Keynote::Presenter
|
47
|
+
presents :model
|
48
|
+
|
49
|
+
def some_bad_js
|
50
|
+
"<script>alert('pwnt');</script>"
|
51
|
+
end
|
52
|
+
|
53
|
+
def some_bad_html
|
54
|
+
html do
|
55
|
+
div { text some_bad_js }
|
56
|
+
div { some_bad_js }
|
57
|
+
div some_bad_js
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Normal
|
63
|
+
end
|
64
|
+
|
65
|
+
module Keynote
|
66
|
+
class NestedPresenter < Keynote::Presenter
|
67
|
+
presents :model
|
68
|
+
|
69
|
+
def generate_div
|
70
|
+
html do
|
71
|
+
div.hi! do
|
72
|
+
link_to '#', 'Hello'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Nested
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class CombinedPresenter < Keynote::Presenter
|
83
|
+
presents :model_1, :model_2
|
84
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe Keynote do
|
6
|
+
describe "with a normal presenter" do
|
7
|
+
let(:model) { Normal.new }
|
8
|
+
|
9
|
+
it "should find and instantiate implicitly" do
|
10
|
+
p = Keynote.present(:view, model)
|
11
|
+
|
12
|
+
p.wont_be_nil
|
13
|
+
p.must_be_instance_of NormalPresenter
|
14
|
+
|
15
|
+
p.view.must_equal :view
|
16
|
+
p.model.must_equal model
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should find and instantiate explicitly" do
|
20
|
+
p = Keynote.present(:view, :normal, 'hello')
|
21
|
+
|
22
|
+
p.wont_be_nil
|
23
|
+
p.must_be_instance_of NormalPresenter
|
24
|
+
|
25
|
+
p.view.must_equal :view
|
26
|
+
p.model.must_equal 'hello'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should integrate with Rumble" do
|
30
|
+
p = Keynote.present(:view, model)
|
31
|
+
rx = /<div><script>alert\(/
|
32
|
+
|
33
|
+
p.some_bad_html.scan(rx).count.must_equal 3
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "with a nested presenter" do
|
38
|
+
let(:model) { Keynote::Nested.new }
|
39
|
+
|
40
|
+
it "should find and instantiate implicitly" do
|
41
|
+
p = Keynote.present(:view, model)
|
42
|
+
|
43
|
+
p.wont_be_nil
|
44
|
+
p.must_be_instance_of Keynote::NestedPresenter
|
45
|
+
|
46
|
+
p.view.must_equal :view
|
47
|
+
p.model.must_equal model
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should find and instantiate explicitly" do
|
51
|
+
p = Keynote.present(:view, :"keynote/nested", 'hello')
|
52
|
+
|
53
|
+
p.wont_be_nil
|
54
|
+
p.must_be_instance_of Keynote::NestedPresenter
|
55
|
+
|
56
|
+
p.view.must_equal :view
|
57
|
+
p.model.must_equal 'hello'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "memoization" do
|
62
|
+
it "should memoize on the model instance(s)" do
|
63
|
+
model_1 = Normal.new
|
64
|
+
model_2 = Normal.new
|
65
|
+
|
66
|
+
presented_1 = Keynote.present(:view, model_1)
|
67
|
+
presented_2 = Keynote.present(:view, model_1)
|
68
|
+
|
69
|
+
presented_1.must_be :equal?, presented_2
|
70
|
+
|
71
|
+
presented_3 = Keynote.present(:view, :combined, model_1, model_2)
|
72
|
+
presented_4 = Keynote.present(:view, :combined, model_1, model_2)
|
73
|
+
presented_5 = Keynote.present(:view, :combined, model_2, model_1)
|
74
|
+
|
75
|
+
presented_3.wont_be :equal?, presented_1
|
76
|
+
presented_3.must_be :equal?, presented_4
|
77
|
+
presented_3.wont_be :equal?, presented_5
|
78
|
+
end
|
79
|
+
|
80
|
+
it "shouldn't memoize if there are no models" do
|
81
|
+
presenter_1 = Keynote.present(:view, :empty)
|
82
|
+
presenter_2 = Keynote.present(:view, :empty)
|
83
|
+
|
84
|
+
presenter_1.wont_be :equal?, presenter_2
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should update the view every time" do
|
88
|
+
model = Normal.new
|
89
|
+
|
90
|
+
presenter_1 = Keynote.present(:view, model)
|
91
|
+
presenter_1.view.must_equal :view
|
92
|
+
|
93
|
+
presenter_2 = Keynote.present(:view_2, model)
|
94
|
+
presenter_2.must_be :equal?, presenter_1
|
95
|
+
presenter_2.view.must_equal :view_2
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
TestPresenter = Keynote::Presenter
|
6
|
+
|
7
|
+
describe Keynote::Presenter do
|
8
|
+
describe "delegation" do
|
9
|
+
let(:klass) do
|
10
|
+
Class.new(TestPresenter) do
|
11
|
+
presents :grizzly, :bear
|
12
|
+
delegate :adams, :to => :grizzly
|
13
|
+
delegate :man, :to => :grizzly, :prefix => true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to use ActiveSupport Module#delegate method" do
|
18
|
+
mock = mock()
|
19
|
+
mock.expects(:adams)
|
20
|
+
mock.expects(:man)
|
21
|
+
|
22
|
+
klass.new(nil, mock, nil).tap do |p|
|
23
|
+
p.adams
|
24
|
+
p.grizzly_man
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".presents" do
|
30
|
+
it "should take just the view context by default" do
|
31
|
+
klass = Class.new(TestPresenter)
|
32
|
+
|
33
|
+
klass.new(1).instance_variable_get(:@view).must_equal 1
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "with two parameters" do
|
37
|
+
let(:klass) do
|
38
|
+
Class.new(TestPresenter) do
|
39
|
+
presents :grizzly, :bear
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should let you specify other objects to take" do
|
44
|
+
klass.new(1, 2, 3).instance_eval do
|
45
|
+
@view.must_equal 1
|
46
|
+
@grizzly.must_equal 2
|
47
|
+
@bear.must_equal 3
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not be callable with the wrong arity" do
|
52
|
+
proc { klass.new(1, 2) }.must_raise ArgumentError
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should generate readers for the objects" do
|
56
|
+
klass.new(1, 2, 3).tap do |p|
|
57
|
+
p.view.must_equal 1
|
58
|
+
p.grizzly.must_equal 2
|
59
|
+
p.bear.must_equal 3
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#present" do
|
66
|
+
it "should pass its view context through to the new presenter" do
|
67
|
+
mock = mock()
|
68
|
+
mock.expects(:pizza)
|
69
|
+
|
70
|
+
p1 = TestPresenter.new(mock)
|
71
|
+
p2 = p1.present(:test)
|
72
|
+
|
73
|
+
p1.wont_equal p2
|
74
|
+
p2.pizza
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#method_missing" do
|
79
|
+
it "should pass unknown method calls through to the view" do
|
80
|
+
mock = mock()
|
81
|
+
mock.expects(:talking).with(:heads)
|
82
|
+
|
83
|
+
object = Class.new do
|
84
|
+
define_method(:talking) do |arg|
|
85
|
+
mock.talking(arg)
|
86
|
+
end
|
87
|
+
private :talking
|
88
|
+
end.new
|
89
|
+
|
90
|
+
TestPresenter.new(object).talking(:heads)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should respond_to? methods of the view" do
|
94
|
+
object = Class.new do
|
95
|
+
define_method(:talking) do |arg|
|
96
|
+
end
|
97
|
+
private :talking
|
98
|
+
end.new
|
99
|
+
|
100
|
+
TestPresenter.new(object).respond_to?(:talking).must_equal true
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should raise unknown methods at the presenter, not the view" do
|
104
|
+
err = nil
|
105
|
+
|
106
|
+
begin
|
107
|
+
TestPresenter.new(Object.new).talking(:heads)
|
108
|
+
rescue NoMethodError => e
|
109
|
+
err = e
|
110
|
+
end
|
111
|
+
|
112
|
+
err.wont_be_nil
|
113
|
+
err.message.must_match /#<Keynote::Presenter:/
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe Keynote::Railtie do
|
6
|
+
let(:controller) { HelloController.new }
|
7
|
+
let(:context) { controller.view_context }
|
8
|
+
|
9
|
+
it "should make the present method available to controllers" do
|
10
|
+
controller.must_respond_to :present
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should make the present and p methods available to views" do
|
14
|
+
context.must_respond_to :present
|
15
|
+
context.must_respond_to :p
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should pass present call from controller to Keynote.present" do
|
19
|
+
context = stub
|
20
|
+
controller.stubs(:view_context).returns(context)
|
21
|
+
|
22
|
+
Keynote.expects(:present).with(context, :dallas, :leeloo, :multipass)
|
23
|
+
|
24
|
+
controller.present(:dallas, :leeloo, :multipass)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should pass present call from view to Keynote.present" do
|
28
|
+
Keynote.expects(:present).with(context, :dallas, :leeloo, :multipass)
|
29
|
+
|
30
|
+
context.present(:dallas, :leeloo, :multipass)
|
31
|
+
end
|
32
|
+
end
|