display_case 0.0.1 → 0.0.2
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/README.md +2 -1
- data/lib/display_case/enumerable_exhibit.rb +43 -41
- data/lib/display_case/exhibit.rb +100 -98
- data/lib/display_case/exhibits_helper.rb +6 -4
- metadata +3 -3
data/README.md
CHANGED
@@ -31,7 +31,7 @@ Your exhibits will look something like this:
|
|
31
31
|
``` ruby
|
32
32
|
# app/exhibits/league_exhibit.rb
|
33
33
|
|
34
|
-
class LeagueExhibit < Exhibit
|
34
|
+
class LeagueExhibit < DisplayCase::Exhibit
|
35
35
|
def self.applicable_to?(object)
|
36
36
|
object.class.name == 'League'
|
37
37
|
end
|
@@ -46,6 +46,7 @@ Then in your controller, where you're instantiating a League, wrap it in a call
|
|
46
46
|
``` ruby
|
47
47
|
# app/controllers/leagues_controller.rb
|
48
48
|
class LeaguesController < ApplicationController
|
49
|
+
include DisplayCase::ExhibitsHelper
|
49
50
|
# ...
|
50
51
|
def index
|
51
52
|
# display_case automatically wraps the individual objects contained in
|
@@ -1,53 +1,55 @@
|
|
1
1
|
require_relative 'exhibit'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module DisplayCase
|
4
|
+
class EnumerableExhibit < Exhibit
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def self.applicable_to?(object)
|
8
|
+
# ActiveRecord::Relation, surprisingly, is not Enumerable. But it
|
9
|
+
# behaves sufficiently similarly for our purposes.
|
10
|
+
object_is_any_of?(object, 'Enumerable', 'ActiveRecord::Relation')
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
# Wrap an Enumerable method which returns another collection
|
14
|
+
def self.exhibit_enum(*method_names, &post_process)
|
15
|
+
post_process ||= ->(result){exhibit(result)}
|
16
|
+
method_names.each do |method_name|
|
17
|
+
define_method(method_name) do |*args, &block|
|
18
|
+
result = __getobj__.public_send(method_name, *args, &block)
|
19
|
+
instance_exec(result, &post_process)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
22
|
-
private_class_method :exhibit_enum
|
23
|
+
private_class_method :exhibit_enum
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
exhibit_query :[], :fetch, :slice, :values_at, :last
|
26
|
+
exhibit_enum :select, :grep, :reject, :to_enum, :sort, :sort_by, :reverse
|
27
|
+
exhibit_enum :partition do |result|
|
28
|
+
result.map{|group| exhibit(group)}
|
29
|
+
end
|
30
|
+
exhibit_enum :group_by do |result|
|
31
|
+
result.inject({}) { |h,(k,v)|
|
32
|
+
h.merge!(k => exhibit(v))
|
33
|
+
}
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def each(*)
|
37
|
+
super do |e|
|
38
|
+
yield exhibit(e)
|
39
|
+
end
|
38
40
|
end
|
39
|
-
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
# `render '...', :collection => self` will call #to_ary on this
|
43
|
+
# before rendering, so we need to be prepared.
|
44
|
+
def to_ary
|
45
|
+
self
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def render(template)
|
49
|
+
inject(ActiveSupport::SafeBuffer.new) { |output,element|
|
50
|
+
output << element.render(template)
|
51
|
+
}
|
52
|
+
end
|
52
53
|
|
54
|
+
end
|
53
55
|
end
|
data/lib/display_case/exhibit.rb
CHANGED
@@ -2,129 +2,131 @@ require 'delegate'
|
|
2
2
|
require 'active_support/core_ext'
|
3
3
|
require 'display_case/railtie' if defined?(Rails)
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
module DisplayCase
|
6
|
+
class Exhibit < SimpleDelegator
|
7
|
+
@@exhibits = []
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def self.exhibits
|
10
|
+
@@exhibits
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def self.inherited(child)
|
14
|
+
@@exhibits << child
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
def self.exhibit(object, context)
|
18
|
+
return object if exhibited_object?(object)
|
19
|
+
Rails.logger.debug "Registered exhibits: #{@@exhibits}"
|
20
|
+
Rails.logger.debug "Exhibiting #{object.inspect}"
|
21
|
+
Rails.logger.debug "Exhibit context: #{context}"
|
22
|
+
object = Exhibited.new(object, context)
|
23
|
+
exhibits.inject(object) do |object, exhibit_class|
|
24
|
+
exhibit_class.exhibit_if_applicable(object, context)
|
25
|
+
end.tap do |obj|
|
26
|
+
Rails.logger.debug "Exhibits applied: #{obj.inspect_exhibits}"
|
27
|
+
end
|
26
28
|
end
|
27
|
-
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def self.exhibit_if_applicable(object, context)
|
31
|
+
if applicable_to?(object)
|
32
|
+
new(object, context)
|
33
|
+
else
|
34
|
+
object
|
35
|
+
end
|
34
36
|
end
|
35
|
-
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def self.applicable_to?(object)
|
39
|
+
false
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
def self.exhibited_object?(object)
|
43
|
+
object.respond_to?(:exhibited?) && object.exhibited?
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
def self.exhibit_query(*method_names)
|
47
|
+
method_names.each do |name|
|
48
|
+
define_method(name) do |*args, &block|
|
49
|
+
exhibit(super(*args, &block))
|
50
|
+
end
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
private_class_method :object_is_any_of?
|
53
|
+
private_class_method :exhibit_query
|
54
|
+
|
55
|
+
# A helper for matching models to classes/modules, intended for use
|
56
|
+
# in .applicable_to?.
|
57
|
+
def self.object_is_any_of?(object, *classes)
|
58
|
+
# What with Rails development mode reloading making class matching
|
59
|
+
# unreliable, plus wanting to avoid adding dependencies to
|
60
|
+
# external class definitions if we can avoid it, we just match
|
61
|
+
# against class/module name strings rather than the actual class
|
62
|
+
# objects.
|
63
|
+
|
64
|
+
# Note that '&' is the set intersection operator for Arrays.
|
65
|
+
(classes.map(&:to_s) & object.class.ancestors.map(&:name)).any?
|
66
|
+
end
|
67
|
+
private_class_method :object_is_any_of?
|
67
68
|
|
68
|
-
|
69
|
+
attr_reader :context
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
def initialize(model, context)
|
72
|
+
@context = context
|
73
|
+
super(model)
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
alias_method :__class__, :class
|
77
|
+
def class
|
78
|
+
__getobj__.class
|
79
|
+
end
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
def exhibit(model)
|
82
|
+
Exhibit.exhibit(model, context)
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
def to_partial_path
|
86
|
+
if __getobj__.respond_to?(:to_partial_path)
|
87
|
+
__getobj__.to_partial_path
|
88
|
+
else
|
89
|
+
partialize_name(__getobj__.class.name)
|
90
|
+
end
|
89
91
|
end
|
90
|
-
end
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
def render(template)
|
94
|
+
template.render(:partial => to_partial_path, :object => self)
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
97
|
+
def exhibit_chain
|
98
|
+
inner_exhibits = defined?(super) ? super : []
|
99
|
+
[__class__] + inner_exhibits
|
100
|
+
end
|
100
101
|
|
101
|
-
|
102
|
-
|
103
|
-
|
102
|
+
def inspect_exhibits
|
103
|
+
exhibit_chain.map(&:to_s).join(':')
|
104
|
+
end
|
104
105
|
|
105
|
-
|
106
|
-
|
107
|
-
|
106
|
+
def inspect
|
107
|
+
"#{inspect_exhibits}(#{__getobj__.inspect})"
|
108
|
+
end
|
108
109
|
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
def exhibited?
|
111
|
+
true
|
112
|
+
end
|
112
113
|
|
113
|
-
|
114
|
+
private
|
114
115
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
# The terminator for the exhibit chain, and a marker that an object
|
117
|
+
# has been through the exhibit process
|
118
|
+
class Exhibited < Exhibit
|
119
|
+
def exhibit_chain
|
120
|
+
[]
|
121
|
+
end
|
121
122
|
|
122
|
-
|
123
|
-
|
123
|
+
def to_model
|
124
|
+
__getobj__
|
125
|
+
end
|
124
126
|
end
|
125
|
-
end
|
126
127
|
|
127
|
-
|
128
|
-
|
128
|
+
def partialize_name(name)
|
129
|
+
"/#{name.underscore.pluralize}/#{name.demodulize.underscore}"
|
130
|
+
end
|
129
131
|
end
|
130
|
-
end
|
132
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: display_case
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-23 00:00:00.
|
12
|
+
date: 2012-05-23 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: An implementation of the Exhibit pattern, as described in Objects on
|
15
15
|
Rails
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
47
|
version: '0'
|
48
48
|
requirements: []
|
49
49
|
rubyforge_project:
|
50
|
-
rubygems_version: 1.8.
|
50
|
+
rubygems_version: 1.8.10
|
51
51
|
signing_key:
|
52
52
|
specification_version: 3
|
53
53
|
summary: An implementation of the Exhibit pattern, as described in Objects on Rails
|