magic-presenter 1.2.0 → 1.4.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.
- checksums.yaml +4 -4
- data/README.md +44 -0
- data/app/models/concerns/magic/presentable/active_record_collection.rb +15 -0
- data/app/models/concerns/magic/presentable/collection.rb +19 -0
- data/app/models/concerns/magic/presentable.rb +4 -0
- data/config/initializers/action_view.rb +10 -0
- data/config/initializers/presentable.rb +4 -0
- data/lib/magic/presenter/base.rb +30 -0
- data/lib/magic/presenter/collection.rb +36 -0
- data/lib/magic/presenter/engine.rb +1 -1
- data/lib/magic/presenter/helpers.rb +2 -1
- data/lib/magic/presenter/version.rb +1 -1
- data/lib/magic/presenter.rb +7 -6
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 018f8d173f204bef93fdaf99a35417b1018a81517231f673a0dd44a1644ee61b
|
|
4
|
+
data.tar.gz: e0ca0e5a3b439b40e20d429f7f7ba35c48390f51debb30510445d4e1d682b948
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c2913873efd49741bf0991eb34cfd30e32ceede34a84eef752b86c951625cd173db3b4069473f16a0ecfc6e1ea8d26c9a75a8d8525a4e35c5d8e81e38346841
|
|
7
|
+
data.tar.gz: e28356ed613cc0f68f46618ba989956fd3dd467d91ec0bf81f1d9aced9f6504208a7dedff8ebd05bdfcb2bf7214d5dadc97ba961738928ee2fe09578a7b66eb5
|
data/README.md
CHANGED
|
@@ -55,6 +55,8 @@ person = Person.new(first_name: 'John', last_name: 'Smith').decorate
|
|
|
55
55
|
person.name # => "John Smith"
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
Use [load hooks](#load-hooks) to extend the base presenter functionality.
|
|
59
|
+
|
|
58
60
|
### `Magic::Presentable`
|
|
59
61
|
|
|
60
62
|
This module includes `Magic::Decoratable` and allows a descendant to be decorated by presenters only.
|
|
@@ -64,6 +66,26 @@ When no presenter is found,
|
|
|
64
66
|
- `#decorate!` raises `Magic::Lookup::Error`,
|
|
65
67
|
- `#decorated` returns the original object.
|
|
66
68
|
|
|
69
|
+
Use [load hooks](#load-hooks) to extend the functionality.
|
|
70
|
+
|
|
71
|
+
#### Collections
|
|
72
|
+
|
|
73
|
+
Active Record relations are presentable as collections. Define a collection presenter inside the matching presenter to customize collection behavior:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
class PersonPresenter < Magic::Presenter::Base
|
|
77
|
+
collection_presenter do
|
|
78
|
+
def names = map(&:name).to_sentence
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
Person.all.decorated.names
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Under the hood, `.collection_presenter` defines `PersonPresenter::Collection < Magic::Presenter::Collection` in the above example and evaluates the block within that class’ context.
|
|
86
|
+
It looks for a collection presenter class in ancestor classes to be inherited from, up to `Magic::Presenter::Collection`.
|
|
87
|
+
One can also define a collection presenter class explicitly, following the same pattern.
|
|
88
|
+
|
|
67
89
|
### Generators
|
|
68
90
|
|
|
69
91
|
A generator can be used to generate a presenter:
|
|
@@ -103,6 +125,25 @@ end
|
|
|
103
125
|
> [!NOTE]
|
|
104
126
|
> A valid `request` may be needed for URL helpers to get host data.
|
|
105
127
|
|
|
128
|
+
### Load hooks
|
|
129
|
+
|
|
130
|
+
Load hooks are triggered when `Magic::Presenter::Base` or `Magic::Presentable` are loaded.
|
|
131
|
+
They allow you to run custom initialization code for configuration or to extend the functionality.
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
ActiveSupport.on_load :presenter do
|
|
135
|
+
# Put the code to be executed when Magic::Presenter is loaded here.
|
|
136
|
+
# It runs in the context of Magic::Presenter::Base class.
|
|
137
|
+
end
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
ActiveSupport.on_load :presentable do
|
|
142
|
+
# Put the code to be executed when Magic::Presentable is loaded here.
|
|
143
|
+
# It runs in the context of Magic::Presentable module.
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
106
147
|
## 🧙 Magic
|
|
107
148
|
|
|
108
149
|
> [!IMPORTANT]
|
|
@@ -110,6 +151,8 @@ end
|
|
|
110
151
|
> https://github.com/Alexander-Senko/magic-decorator#magic
|
|
111
152
|
> ), so get familiar with that one as well.
|
|
112
153
|
|
|
154
|
+
In short, the phylosophy is: _**define presenters you need and expect them to be applied automagically to all the corresponding objects** in every appropriate (view) context_.
|
|
155
|
+
|
|
113
156
|
### Presentable scope
|
|
114
157
|
|
|
115
158
|
`Magic::Presentable` is mixed into `ActiveModel::API` by default.
|
|
@@ -149,6 +192,7 @@ Missing class methods of a presenter are delegated to a matching model class if
|
|
|
149
192
|
> [!NOTE]
|
|
150
193
|
> Every object passed to views is decorated automagically.
|
|
151
194
|
> This involves both implicit instance variables and `locals` passed explicitly.
|
|
195
|
+
> Controller helper methods are also decorated when called from views.
|
|
152
196
|
|
|
153
197
|
### Helpers
|
|
154
198
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Magic
|
|
4
|
+
module Presentable
|
|
5
|
+
# = Presentable Active Record relation
|
|
6
|
+
#
|
|
7
|
+
# A tiny wrapper around `Presentable::Collection` for Active Record
|
|
8
|
+
# relations.
|
|
9
|
+
module ActiveRecordCollection
|
|
10
|
+
include Collection
|
|
11
|
+
|
|
12
|
+
def model_class = model
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Magic
|
|
4
|
+
module Presentable
|
|
5
|
+
# = Presentable collection
|
|
6
|
+
#
|
|
7
|
+
# This module includes `Magic::Decoratable` and allows a descendant
|
|
8
|
+
# to be decorated by collection presenters only. Presenter class is
|
|
9
|
+
# being inferred automatically from a collection’s model class.
|
|
10
|
+
module Collection
|
|
11
|
+
include Decoratable
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def decorator = decorator_base.for model_class
|
|
16
|
+
def decorator_base = Presenter::Collection
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Magic
|
|
4
|
+
# = Presentable object
|
|
5
|
+
#
|
|
4
6
|
# This module includes `Magic::Decoratable` and allows a descendant
|
|
5
7
|
# to be decorated by presenters only. Presenter class is being
|
|
6
8
|
# inferred automatically.
|
|
@@ -12,4 +14,6 @@ module Magic
|
|
|
12
14
|
|
|
13
15
|
def decorator_base = Presenter::Base
|
|
14
16
|
end
|
|
17
|
+
|
|
18
|
+
ActiveSupport.run_load_hooks :presentable, Presentable
|
|
15
19
|
end
|
|
@@ -22,6 +22,16 @@ ActiveSupport.on_load :action_view do # rubocop:disable Metrics/BlockLength
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
concerning :DecoratedHelpers, prepend: true do
|
|
26
|
+
require 'magic/decorator/core_ext/module'
|
|
27
|
+
|
|
28
|
+
def assign_controller controller
|
|
29
|
+
super
|
|
30
|
+
|
|
31
|
+
self.class.decorated_method controller._helper_methods
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
25
35
|
concerning :PresenterContext, prepend: true do
|
|
26
36
|
def in_rendering_context(...)
|
|
27
37
|
Magic::Presenter.with view_context: self do
|
data/lib/magic/presenter/base.rb
CHANGED
|
@@ -18,6 +18,8 @@ module Magic
|
|
|
18
18
|
include GlobalID if defined? ::GlobalID
|
|
19
19
|
prepend Helpers if defined? ::ActionView
|
|
20
20
|
|
|
21
|
+
Collection = Collection # for lookup
|
|
22
|
+
|
|
21
23
|
class << self
|
|
22
24
|
def name_for object_class
|
|
23
25
|
object_class
|
|
@@ -30,7 +32,35 @@ module Magic
|
|
|
30
32
|
def model_class = Presentable.for self
|
|
31
33
|
|
|
32
34
|
delegate_missing_to :model_class
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# Define collection presenter from the given block.
|
|
39
|
+
#
|
|
40
|
+
# class MyPresenter < Magic::Presenter::Base
|
|
41
|
+
# collection_presenter do
|
|
42
|
+
# def count = "#{super} items"
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# class MyModel < ApplicationRecord
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# MyModel.all.count # => 42
|
|
50
|
+
# MyModel.all.decorated.count # => "42 items"
|
|
51
|
+
#
|
|
52
|
+
# It looks for a collection presenter class in ancestor classes
|
|
53
|
+
# to be inherited from, up to `Magic::Presenter::Collection`.
|
|
54
|
+
def collection_presenter(&)
|
|
55
|
+
if const_defined? :Collection, false
|
|
56
|
+
const_get :Collection
|
|
57
|
+
else
|
|
58
|
+
const_set :Collection, Class.new(const_get :Collection)
|
|
59
|
+
end.class_eval(&)
|
|
60
|
+
end
|
|
33
61
|
end
|
|
34
62
|
end
|
|
63
|
+
|
|
64
|
+
ActiveSupport.run_load_hooks :presenter, Base
|
|
35
65
|
end
|
|
36
66
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Magic
|
|
4
|
+
module Presenter
|
|
5
|
+
# = Collection presenter
|
|
6
|
+
#
|
|
7
|
+
# This presenter is used as a base class to decorate typed
|
|
8
|
+
# collections (e.g., Active Record relations).
|
|
9
|
+
#
|
|
10
|
+
# == Presenter class inference
|
|
11
|
+
#
|
|
12
|
+
# Collection presenters provide automatic class inference for any
|
|
13
|
+
# typed collection based on the class name of its elements powered
|
|
14
|
+
# by Magic Lookup.
|
|
15
|
+
# For example, a collection of `MyRecord`s (e.g., `MyRecord.all`)
|
|
16
|
+
# looks for `MyPresenter::Collection` first.
|
|
17
|
+
# If not found, it looks for collection presenters of its ancestor
|
|
18
|
+
# classes, up to `ObjectPresenter::Collection`.
|
|
19
|
+
class Collection < EnumerableDecorator
|
|
20
|
+
prepend Helpers if defined? ::ActionView
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def name_for(...) = Base.name_for(...)
|
|
24
|
+
.concat('::Collection')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def item_presenter = model_class
|
|
28
|
+
&.then { Presenter.for it }
|
|
29
|
+
|
|
30
|
+
def model_class = __getobj__
|
|
31
|
+
.try :model_class
|
|
32
|
+
|
|
33
|
+
def to_a(...) = self.class.new super
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/magic/presenter.rb
CHANGED
|
@@ -5,14 +5,15 @@ require 'magic/decorator'
|
|
|
5
5
|
require_relative 'presenter/version'
|
|
6
6
|
require_relative 'presenter/engine'
|
|
7
7
|
|
|
8
|
-
module Magic
|
|
8
|
+
module Magic
|
|
9
9
|
# Presentation layer for Rails models
|
|
10
10
|
module Presenter
|
|
11
|
-
autoload :Base,
|
|
12
|
-
autoload :
|
|
13
|
-
autoload :
|
|
14
|
-
autoload :
|
|
15
|
-
autoload :
|
|
11
|
+
autoload :Base, 'magic/presenter/base'
|
|
12
|
+
autoload :Collection, 'magic/presenter/collection'
|
|
13
|
+
autoload :Helpers, 'magic/presenter/helpers'
|
|
14
|
+
autoload :GlobalID, 'magic/presenter/global_id'
|
|
15
|
+
autoload :TestCase, 'magic/presenter/test_case'
|
|
16
|
+
autoload :Generator, 'generators/magic/presenter/generator'
|
|
16
17
|
|
|
17
18
|
singleton_class.delegate *%i[
|
|
18
19
|
for name_for
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: magic-presenter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Senko
|
|
@@ -40,7 +40,7 @@ dependencies:
|
|
|
40
40
|
-
|
|
41
41
|
- ~>
|
|
42
42
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: "1.
|
|
43
|
+
version: "1.2"
|
|
44
44
|
type: :runtime
|
|
45
45
|
prerelease: false
|
|
46
46
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -48,7 +48,7 @@ dependencies:
|
|
|
48
48
|
-
|
|
49
49
|
- ~>
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
|
-
version: "1.
|
|
51
|
+
version: "1.2"
|
|
52
52
|
- !ruby/object:Gem::Dependency
|
|
53
53
|
name: magic-lookup
|
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -76,6 +76,8 @@ files:
|
|
|
76
76
|
- README.md
|
|
77
77
|
- Rakefile
|
|
78
78
|
- app/models/concerns/magic/presentable.rb
|
|
79
|
+
- app/models/concerns/magic/presentable/active_record_collection.rb
|
|
80
|
+
- app/models/concerns/magic/presentable/collection.rb
|
|
79
81
|
- config/initializers/action_controller.rb
|
|
80
82
|
- config/initializers/action_view.rb
|
|
81
83
|
- config/initializers/generators.rb
|
|
@@ -95,6 +97,7 @@ files:
|
|
|
95
97
|
- lib/magic/presenter.rb
|
|
96
98
|
- lib/magic/presenter/authors.rb
|
|
97
99
|
- lib/magic/presenter/base.rb
|
|
100
|
+
- lib/magic/presenter/collection.rb
|
|
98
101
|
- lib/magic/presenter/engine.rb
|
|
99
102
|
- lib/magic/presenter/global_id.rb
|
|
100
103
|
- lib/magic/presenter/helpers.rb
|
|
@@ -108,7 +111,7 @@ licenses:
|
|
|
108
111
|
metadata:
|
|
109
112
|
homepage_uri: "https://github.com/Alexander-Senko/magic-presenter"
|
|
110
113
|
source_code_uri: "https://github.com/Alexander-Senko/magic-presenter"
|
|
111
|
-
changelog_uri: "https://github.com/Alexander-Senko/magic-presenter/blob/v1.
|
|
114
|
+
changelog_uri: "https://github.com/Alexander-Senko/magic-presenter/blob/v1.4.0/CHANGELOG.md"
|
|
112
115
|
rdoc_options: []
|
|
113
116
|
require_paths:
|
|
114
117
|
- lib
|