assaf-presenter 0.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/CHANGELOG +0 -0
- data/MIT-LICENSE +0 -0
- data/README +0 -0
- data/Rakefile +23 -0
- data/lib/presenter.rb +9 -0
- data/lib/presenter/base.rb +115 -0
- data/lib/presenter/method.rb +46 -0
- data/lib/presenter/rspec.rb +33 -0
- data/presenter.gemspec +22 -0
- data/rails/init.rb +9 -0
- data/spec/helper.rb +15 -0
- data/spec/presenter_spec.rb +73 -0
- data/spec/presenting_method_spec.rb +111 -0
- metadata +82 -0
data/CHANGELOG
ADDED
File without changes
|
data/MIT-LICENSE
ADDED
File without changes
|
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
|
3
|
+
|
4
|
+
spec = Gem::Specification.load(File.join(File.dirname(__FILE__), 'presenter.gemspec'))
|
5
|
+
|
6
|
+
task 'setup' do
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
package = Rake::GemPackageTask.new(spec) do |pkg|
|
11
|
+
pkg.need_tar = true
|
12
|
+
pkg.need_zip = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Install the package locally"
|
16
|
+
task 'install'=>['setup', 'package'] do |task|
|
17
|
+
system 'sudo', 'gem', 'install', "pkg/#{spec.name}-#{spec.version}.gem"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Uninstall previously installed packaged"
|
21
|
+
task 'uninstall' do |task|
|
22
|
+
system 'sudo', 'gem', 'uninstall', spec.name, '-v', spec.version.to_s
|
23
|
+
end
|
data/lib/presenter.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module Presenter
|
2
|
+
class Base
|
3
|
+
|
4
|
+
class << self
|
5
|
+
# Item name, derived from the class name (e.g. TaskPresenter becomes 'task').
|
6
|
+
# Used for the XML document element name, also name of the accessor method used
|
7
|
+
# to read the presented object.
|
8
|
+
attr_reader :item_name
|
9
|
+
|
10
|
+
# Array name, derived from the class name (e.g. TaskPresenter becomes 'tasks').
|
11
|
+
# Used for the XML document element name, also name of the accessor method used
|
12
|
+
# to read the presented array of objects.
|
13
|
+
attr_reader :array_name
|
14
|
+
|
15
|
+
def inherited(klass)
|
16
|
+
name = klass.name[/(.*?)(Presenter)?$/, 1].underscore
|
17
|
+
klass.instance_variable_set(:@item_name, name)
|
18
|
+
klass.class_eval "def #{klass.item_name} ; @item ; end"
|
19
|
+
klass.instance_variable_set(:@array_name, name.pluralize)
|
20
|
+
klass.class_eval "def #{klass.array_name} ; @array ; end"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates new presenter using the given controller and item/array.
|
26
|
+
def initialize(controller, value)
|
27
|
+
@controller = controller
|
28
|
+
if value.is_a?(Array)
|
29
|
+
@array = value
|
30
|
+
else
|
31
|
+
@item = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
include PresentingMethod
|
36
|
+
|
37
|
+
# Controller associated with this presenter. Used primarily to create URLs
|
38
|
+
# and access various helper methods.
|
39
|
+
attr_reader :controller
|
40
|
+
|
41
|
+
# Item being presented. This accessor has a value when presenting a single
|
42
|
+
# object, for arrays see #array. Can also be accessed from named attribute,
|
43
|
+
# e.g. the #task method on TaskPresenter.
|
44
|
+
attr_reader :item
|
45
|
+
|
46
|
+
# Array being presented. This accessor has a value when presenting an array
|
47
|
+
# of objects, for single item see #item. Can also be accessed from named attribute,
|
48
|
+
# e.g. the #tasks method on TaskPresenter.
|
49
|
+
attr_reader :array
|
50
|
+
|
51
|
+
# Converts to JSON document, returns a String. The default implementation
|
52
|
+
# uses #map to convert the instance or each member of the array, and calls
|
53
|
+
# #to_json on the result.
|
54
|
+
#
|
55
|
+
# For example:
|
56
|
+
# render :json=>presenting(@item)
|
57
|
+
def to_json(options = {})
|
58
|
+
@array ? @array.map { |i| hash_for(i) }.to_json(options) :
|
59
|
+
hash_for(@item).to_json(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Converts to XML document, returns a String. The default implementation
|
63
|
+
# uses #map to convert the instance or each member of the array, and calls
|
64
|
+
# #to_xml on the result.
|
65
|
+
#
|
66
|
+
# For example:
|
67
|
+
# render :xml=>presenting(@items)
|
68
|
+
def to_xml(options = {})
|
69
|
+
@array ? @array.map { |i| hash_for(i) }.to_xml({:root=>self.class.array_name}.merge(options)) :
|
70
|
+
hash_for(@item).to_xml({:root=>self.class.item_name}.merge(options))
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
# Shortcut for CGI::escapeHTML.
|
76
|
+
def h(text)
|
77
|
+
CGI::escapeHTML(text)
|
78
|
+
end
|
79
|
+
|
80
|
+
include ActionController::UrlWriter
|
81
|
+
# TODO: do we need this?
|
82
|
+
# default_url_options[:host] = 'test.host' if defined?(RAILS_ENV) && RAILS_ENV == 'test'
|
83
|
+
|
84
|
+
def url_for_with_controller(*args)
|
85
|
+
if controller
|
86
|
+
controller.url_for(*args)
|
87
|
+
else
|
88
|
+
url_for_without_controller(*args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
alias_method_chain :url_for, :controller
|
92
|
+
|
93
|
+
# Request to which this controller is responding.
|
94
|
+
def request
|
95
|
+
controller && controller.request
|
96
|
+
end
|
97
|
+
|
98
|
+
# Converts object into a hash. JSON, XML and other output formats use this
|
99
|
+
# before serializing the result into the respective content type.
|
100
|
+
#
|
101
|
+
# Override to do all sorts of fancy tricks. The defult implementation calls
|
102
|
+
# the attributes methods (works on ActiveRecord models), lacking that the to_hash
|
103
|
+
# method, and if neither is found return an empty hash.
|
104
|
+
def hash_for(object)
|
105
|
+
object.respond_to?(:attributes) && object.attributes ||
|
106
|
+
object.respond_to?(:to_hash) && object.to_hash || {}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns an ID using the host name, object class and object identifier.
|
110
|
+
def id_for(object)
|
111
|
+
"tag:#{request.host}:#{object.class.underscore}/#{object.id}"
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Presenter
|
2
|
+
module PresentingMethod
|
3
|
+
|
4
|
+
# Return a new presenter. This method can be called in several configurations to
|
5
|
+
# present both an instance and an array:
|
6
|
+
#
|
7
|
+
# You can call this method in several configurations to present both singular objects
|
8
|
+
# and arrays. Using an explicit type followed by value:
|
9
|
+
# presenting(class, object_or_array)
|
10
|
+
# The first argument specifies the expected type of the object/array that follows,
|
11
|
+
# and that argument is used to find the presenter class. For example, <tt>presenting(Foo,[])<tt>
|
12
|
+
# uses <tt>FooPresenter</tt>.
|
13
|
+
# presenting(symbol, object_or_array)
|
14
|
+
# This method is similar but replaces explicit class with symbol, so <tt>foo:<tt> instead
|
15
|
+
# of <tt>Foo</tt>.
|
16
|
+
# presenting(object)
|
17
|
+
# The third form takes a single argument and finds the presenter class based on the
|
18
|
+
# argument type, for example, <tt>presenting(Foo.new)</tt> will use the presenter class
|
19
|
+
# <tt>FooPresenter</tt>.
|
20
|
+
# presenting(array)
|
21
|
+
# Since arrays may be empty it is not always possible to use the array content to figure
|
22
|
+
# out the presenter class. Either specify it explicitly as the first argument (see above),
|
23
|
+
# or let the presenting method figure it out from the controller name, for example,
|
24
|
+
# inferring <tt>FooPresenter</tt> from <tt>FooController</tt>.
|
25
|
+
def presenting(*args)
|
26
|
+
controller = ActionController::Base === self ? self : self.controller
|
27
|
+
case args.first
|
28
|
+
when Class # Presented class followed by instance/array
|
29
|
+
name = args.shift.to_s
|
30
|
+
value = args.shift
|
31
|
+
when Symbol # Presenter name (symbol) followed by instance/array
|
32
|
+
name = args.shift.to_s.capitalize
|
33
|
+
value = args.shift
|
34
|
+
when Array # Array of values, pick presenter from item type
|
35
|
+
value = args.shift
|
36
|
+
name = controller.class.to_s.gsub(/Controller$/, '').classify
|
37
|
+
else # Presenter for single instance.
|
38
|
+
value = args.shift
|
39
|
+
name = value.class.name
|
40
|
+
end
|
41
|
+
raise ArgumentError, "Unexpected arguments #{args.inspect}" unless args.empty?
|
42
|
+
Class.const_get("#{name}Presenter").new(controller, value)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Spec
|
2
|
+
module Rails
|
3
|
+
module Matchers
|
4
|
+
|
5
|
+
class PresentMatcher
|
6
|
+
def initialize(presenter, format)
|
7
|
+
@presenter = presenter
|
8
|
+
@format = format
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(response)
|
12
|
+
@expect = response.body
|
13
|
+
@actual = @presenter.send("to_#{@format.to_sym}")
|
14
|
+
@actual == @expect
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message
|
18
|
+
"Expected #{@expect.inspect}, found #{@actual.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def negative_failure_message
|
22
|
+
"Found unexpected #{@actual.inspect}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include Presenter::PresentingMethod
|
27
|
+
|
28
|
+
def present(*args)
|
29
|
+
PresentMatcher.new(presenting(*args), request.format)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/presenter.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'presenter'
|
3
|
+
spec.version = '0.1.0'
|
4
|
+
spec.author = 'Rails Presenter'
|
5
|
+
spec.email = 'assaf@labnotes.org'
|
6
|
+
spec.homepage = "http://github.com/assaf/#{spec.name}"
|
7
|
+
spec.summary = "Add later ..." # TODO
|
8
|
+
|
9
|
+
spec.files = Dir['lib/**/*', 'rails/**/*', 'README', 'CHANGELOG', 'MIT-LICENSE',
|
10
|
+
'*.gemspec', 'Rakefile', 'spec/**/*', 'doc/**/*']
|
11
|
+
spec.require_paths = 'lib'
|
12
|
+
|
13
|
+
spec.has_rdoc = true
|
14
|
+
spec.extra_rdoc_files = 'README', 'CHANGELOG', 'MIT-LICENSE'
|
15
|
+
spec.rdoc_options = '--title', spec.name,
|
16
|
+
'--main', 'README', '--line-numbers', '--inline-source',
|
17
|
+
'--webcvs', "#{spec.homepage}/tree/master"
|
18
|
+
spec.rubyforge_project = spec.name
|
19
|
+
|
20
|
+
# Tested against these dependencies.
|
21
|
+
spec.add_dependency 'rails'
|
22
|
+
end
|
data/rails/init.rb
ADDED
data/spec/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ENV['RAILS_ENV'] ||= 'test'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
|
3
|
+
require 'spec/rails'
|
4
|
+
|
5
|
+
# Object being presented.
|
6
|
+
class Foo
|
7
|
+
end
|
8
|
+
|
9
|
+
# Presenter for Foo.
|
10
|
+
class FooPresenter < Presenter::Base
|
11
|
+
end
|
12
|
+
|
13
|
+
# Test controller, using similar name so we can deduct presenter from controller.
|
14
|
+
class FooController < ApplicationController
|
15
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe 'Presenter', :type=>:controller do
|
5
|
+
controller_name :foo
|
6
|
+
|
7
|
+
it 'should derive item name from class name' do
|
8
|
+
FooPresenter.item_name.should == 'foo'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should derive array name from element name' do
|
12
|
+
FooPresenter.array_name.should == 'foos'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have accessor for controller' do
|
16
|
+
presenting(Foo.new).controller.should == controller
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '(instance)' do
|
20
|
+
before { @presenter = presenting(@item = Foo.new) }
|
21
|
+
|
22
|
+
it 'should provide object from #item accessor' do
|
23
|
+
@presenter.item.should == @item
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should provide object from (item) accessor' do
|
27
|
+
@presenter.foo.should == @item
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should provide nothing from #array accessor' do
|
31
|
+
@presenter.array.should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should use hash_for(instance) for to_json' do
|
35
|
+
@presenter.should_receive(:hash_for).with(@item).and_return('bar'=>'beer')
|
36
|
+
@presenter.to_json.should == %{{"bar": "beer"}}
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should use hash_for(instance) for to_xml with model name' do
|
40
|
+
@presenter.should_receive(:hash_for).with(@item).and_return('bar'=>'beer')
|
41
|
+
@presenter.to_xml(:indent=>0).should == %{<?xml version=\"1.0\" encoding=\"UTF-8\"?><foo><bar>beer</bar></foo>}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '(array)' do
|
47
|
+
before { @presenter = presenting(@array = [Foo.new, Foo.new]) }
|
48
|
+
|
49
|
+
it 'should provide array from #array accessor' do
|
50
|
+
@presenter.array.should == @array
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should provide array from (array) accessor' do
|
54
|
+
@presenter.foos.should == @array
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should provide nothing from #item accessor' do
|
58
|
+
@presenter.item.should be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should use array.map(hash_for) for to_json' do
|
62
|
+
@presenter.should_receive(:hash_for).twice.and_return({'bar'=>1}, {'bar'=>2})
|
63
|
+
@presenter.to_json.should == %{[{"bar": 1}, {"bar": 2}]}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should use hash_for(instance) for to_xml with model name' do
|
67
|
+
@presenter.should_receive(:hash_for).twice.and_return({'bar'=>1}, {'bar'=>2})
|
68
|
+
@presenter.to_xml(:indent=>0, :types=>false).should == %{<?xml version=\"1.0\" encoding=\"UTF-8\"?><foos type="array"><foo><bar type="integer">1</bar></foo><foo><bar type="integer">2</bar></foo></foos>}
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe 'presenting', :type=>:controller do
|
5
|
+
controller_name :foo
|
6
|
+
|
7
|
+
it 'should be available on controller' do
|
8
|
+
ApplicationController.instance_method(:presenting).to_s.should =~ /presenting/
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be available on view' do
|
12
|
+
ActionView::Base.instance_method(:presenting).to_s.should =~ /presenting/
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should be available on presenter' do
|
16
|
+
FooPresenter.instance_method(:presenting).to_s.should =~ /presenting/
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '(class,instance)' do
|
20
|
+
it 'should guess presenter type from class' do
|
21
|
+
presenting(Foo, 1).should be_kind_of(FooPresenter)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return presenter for instance' do
|
25
|
+
presenting(Foo, 1).item.should == 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '(class,array)' do
|
30
|
+
it 'should guess presenter type from class' do
|
31
|
+
presenting(Foo, [1, 2]).should be_kind_of(FooPresenter)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should return presenter for array' do
|
35
|
+
presenting(Foo, [1, 2]).array.should == [1, 2]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '(symbol,instance)' do
|
40
|
+
it 'should guess presenter type from symbol' do
|
41
|
+
presenting(:foo, 1).should be_kind_of(FooPresenter)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return presenter for instance' do
|
45
|
+
presenting(:foo, 1).item.should == 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '(symbol,array)' do
|
50
|
+
it 'should guess presenter type from class' do
|
51
|
+
presenting(:foo, [1, 2]).should be_kind_of(FooPresenter)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should return presenter for array' do
|
55
|
+
presenting(:foo, [1, 2]).array.should == [1, 2]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '(instance)' do
|
60
|
+
before { @instance = Foo.new }
|
61
|
+
|
62
|
+
it 'should guess presenter type from value' do
|
63
|
+
presenting(@instance).should be_kind_of(FooPresenter)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should return presenter for instance' do
|
67
|
+
presenting(@instance).item.should == @instance
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should fail if value is nil' do
|
71
|
+
lambda { presenting(nil) }.should raise_error(NameError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '(array)' do
|
76
|
+
before { @array = [Foo.new, Foo.new] }
|
77
|
+
|
78
|
+
it 'should guess presenter type from controller' do
|
79
|
+
presenting(@array).should be_kind_of(FooPresenter)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should return presenter for array' do
|
83
|
+
presenting(@array).array.should == @array
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '(empty array)' do
|
88
|
+
before { @empty = [] }
|
89
|
+
|
90
|
+
it 'should guess presenter type from controller' do
|
91
|
+
presenting(@empty).should be_kind_of(FooPresenter)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should return presenter for empty array' do
|
95
|
+
presenting(@empty).array.should be_empty
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should use context as controller if context is controller' do
|
100
|
+
controller.presenting([]).controller.should == controller
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should borrow controller from context if context is not controller' do
|
104
|
+
presenting([]).controller.should == controller
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should fail if passed too many arguments' do
|
108
|
+
lambda { presenting(:foo, [], :bar) }.should raise_error(ArgumentError)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: assaf-presenter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rails Presenter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description:
|
25
|
+
email: assaf@labnotes.org
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
32
|
+
- CHANGELOG
|
33
|
+
- MIT-LICENSE
|
34
|
+
files:
|
35
|
+
- lib/presenter.rb
|
36
|
+
- lib/presenter
|
37
|
+
- lib/presenter/rspec.rb
|
38
|
+
- lib/presenter/base.rb
|
39
|
+
- lib/presenter/method.rb
|
40
|
+
- rails/init.rb
|
41
|
+
- README
|
42
|
+
- CHANGELOG
|
43
|
+
- MIT-LICENSE
|
44
|
+
- presenter.gemspec
|
45
|
+
- Rakefile
|
46
|
+
- spec/presenting_method_spec.rb
|
47
|
+
- spec/presenter_spec.rb
|
48
|
+
- spec/helper.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/assaf/presenter
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --title
|
54
|
+
- presenter
|
55
|
+
- --main
|
56
|
+
- README
|
57
|
+
- --line-numbers
|
58
|
+
- --inline-source
|
59
|
+
- --webcvs
|
60
|
+
- http://github.com/assaf/presenter/tree/master
|
61
|
+
require_paths: lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
version:
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project: presenter
|
77
|
+
rubygems_version: 1.2.0
|
78
|
+
signing_key:
|
79
|
+
specification_version: 2
|
80
|
+
summary: Add later ...
|
81
|
+
test_files: []
|
82
|
+
|