mystique 0.9.1 → 1.0.1
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 +70 -21
- data/lib/mystique.rb +11 -11
- data/lib/mystique/presenter.rb +41 -19
- data/lib/mystique/presenter_class.rb +36 -0
- data/lib/mystique/version.rb +1 -1
- data/mystique.gemspec +2 -3
- metadata +13 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02f8184f7dc42d547bf1a953219e7fc4fbb441a6bc435370a48bd971b218cd8d
|
4
|
+
data.tar.gz: 3e379ef4b394972fc13598a585bcfa8a182e5b1ea62fb33719fba79a37f2caf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c41407e8ae208303733524ff0688d3cb8fe6ff743f2460fd310f547ec06d2a01fa30fd39ce1186053c12f99effbc06e370f3ba697b9ffb52c1a067b402506c18
|
7
|
+
data.tar.gz: ea4e30ff77ded641e3e97915940566a5d72b5e7ea4430c67503bf7ae08157e880a9c3c5905b4e2501839cc827925a8bbe6dd7bdb0b3bfd790ff82579cd2f1a26
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Mystique is a gem that implements the presenter pattern. It allows you to augmen
|
|
4
4
|
|
5
5
|
## How to present
|
6
6
|
|
7
|
-
Mystique ships with the `.present` method, which wraps the target object in a presenter and yield the presenter if a block is given,
|
7
|
+
Mystique ships with the `.present` method, which wraps the target object in a presenter and yield the presenter if a block is given, and returns it. If there default presenter is not available, the original object gets yielded/returned.
|
8
8
|
|
9
9
|
```ruby
|
10
10
|
Item = Struct.new(:name, :price)
|
@@ -26,10 +26,18 @@ The default presenter is inferred from the target object's class name. So, for t
|
|
26
26
|
|
27
27
|
If `ItemPresenter` is not defined, you'll get back your original item.
|
28
28
|
|
29
|
+
```ruby
|
30
|
+
Other = Class.new
|
31
|
+
|
32
|
+
other_presenter = Mystique.present(Other.new)
|
33
|
+
|
34
|
+
other_presenter.class
|
35
|
+
# => Other
|
36
|
+
```
|
29
37
|
|
30
38
|
### Context
|
31
39
|
|
32
|
-
The context is the object that, conveniently, provides the context in which the
|
40
|
+
The context is the object that, conveniently, provides the context in which the original object will be rendered.
|
33
41
|
|
34
42
|
Currently, the context defaults to a null context, which accepts any message sent and does nothing.
|
35
43
|
|
@@ -38,19 +46,34 @@ You can set the context in 3 ways:
|
|
38
46
|
#### Using the `.context` method when defining your presenter:
|
39
47
|
|
40
48
|
```ruby
|
41
|
-
|
42
|
-
|
49
|
+
module UrlHelpers
|
50
|
+
def self.root_path
|
51
|
+
"/"
|
52
|
+
end
|
53
|
+
end
|
43
54
|
|
44
|
-
|
55
|
+
Web = Class.new
|
56
|
+
|
57
|
+
class WebPresenter < Mystique::Presenter
|
58
|
+
context UrlHelpers
|
59
|
+
|
60
|
+
def root
|
61
|
+
h.root_path
|
62
|
+
end
|
45
63
|
end
|
64
|
+
|
65
|
+
web_presenter = Mystique.present(Web.new)
|
66
|
+
|
67
|
+
web_presenter.root
|
68
|
+
# => "/"
|
46
69
|
```
|
47
70
|
|
48
|
-
This will set the `
|
71
|
+
This will set the `UrlHelpers` module as the context for any instance of `WebPresenter`
|
49
72
|
|
50
73
|
#### Passing it to the present method
|
51
74
|
|
52
75
|
```ruby
|
53
|
-
user_presenter = Mystique.present(
|
76
|
+
user_presenter = Mystique.present(some_web_instance, context: UrlHelpers)
|
54
77
|
```
|
55
78
|
|
56
79
|
Which will set `MyHelpers` as the context just for `user_presenter`
|
@@ -64,9 +87,11 @@ but if you pass a new context to a specific instance, it will use that one.
|
|
64
87
|
|
65
88
|
## Formatting
|
66
89
|
|
67
|
-
Mystique provides
|
90
|
+
Mystique provides an `apply_format` method that allows you to define defaults for some response types.
|
91
|
+
|
92
|
+
In every case, `apply_format` will accept a value or a block to return, which will yield the found value and the context.
|
68
93
|
|
69
|
-
In
|
94
|
+
In order to apply that format to a method, you must specify which method by calling `format`. If you forget to do this, Mystique will just retrieve the value from the original object and return that.
|
70
95
|
|
71
96
|
### Specific values
|
72
97
|
|
@@ -75,11 +100,14 @@ This is a great way to return a default String when you get a nil back (but it's
|
|
75
100
|
```ruby
|
76
101
|
Item = Struct.new(:name, :price)
|
77
102
|
class ItemPresenter < Mystique::Presenter
|
78
|
-
format
|
103
|
+
format :price
|
104
|
+
|
105
|
+
apply_format nil, "N/A"
|
79
106
|
end
|
80
107
|
|
81
|
-
item_presenter
|
82
|
-
# => "N/A"
|
108
|
+
Mystique.present(Item.new("Headphones")) do |item_presenter|
|
109
|
+
item_presenter.price # => "N/A"
|
110
|
+
end
|
83
111
|
```
|
84
112
|
|
85
113
|
### Classes
|
@@ -87,11 +115,21 @@ item_presenter.price
|
|
87
115
|
You can pass a class name to the format method, and if the returned value is an instance of that class, it will return the specified value/block
|
88
116
|
|
89
117
|
```ruby
|
118
|
+
module Helpers
|
119
|
+
def self.number_to_currency(number)
|
120
|
+
"$ %0.2f" % number
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
Item = Struct.new(:name, :price)
|
125
|
+
|
90
126
|
class ItemPresenter < Mystique::Presenter
|
91
127
|
context Helpers
|
92
|
-
|
128
|
+
apply_format Float do |value, context|
|
93
129
|
context.number_to_currency(value)
|
94
130
|
end
|
131
|
+
|
132
|
+
format :price
|
95
133
|
end
|
96
134
|
|
97
135
|
item_presenter = Mystique.present(Item.new("Rubik's Cube", 5.3))
|
@@ -111,10 +149,14 @@ module Helpers
|
|
111
149
|
end
|
112
150
|
end
|
113
151
|
|
152
|
+
User = Struct.new(:name, :email)
|
153
|
+
|
114
154
|
class UserPresenter < Mystique::Presenter
|
115
155
|
context Helpers
|
116
156
|
|
117
|
-
format
|
157
|
+
format :email
|
158
|
+
|
159
|
+
apply_format /\w+@\w+\.\w+/ do |email, context|
|
118
160
|
context.link_to(email, "mailto://#{email}")
|
119
161
|
end
|
120
162
|
end
|
@@ -130,16 +172,23 @@ user_presenter.email
|
|
130
172
|
You can also set multiple matchers by using the `.format_multiple` method:
|
131
173
|
|
132
174
|
```ruby
|
133
|
-
|
134
|
-
presenter.class
|
135
|
-
# => ItemPresenter
|
175
|
+
require "time"
|
136
176
|
|
137
|
-
|
138
|
-
# => "$ 50.00"
|
177
|
+
User = Struct.new(:last_log_in)
|
139
178
|
|
140
|
-
|
141
|
-
|
179
|
+
class UserPresenter < Mystique::Presenter
|
180
|
+
format :last_log_in
|
181
|
+
|
182
|
+
format_multiple Date, Time do |value|
|
183
|
+
value.to_date.strftime("%-d %b %Y")
|
184
|
+
end
|
142
185
|
end
|
186
|
+
|
187
|
+
Mystique.present(User.new(Time.now)).last_log_in
|
188
|
+
# => "29 Jul 2020"
|
189
|
+
|
190
|
+
Mystique.present(User.new(Date.today)).last_log_in
|
191
|
+
# => "29 Jul 2020"
|
143
192
|
```
|
144
193
|
|
145
194
|
## Installation
|
data/lib/mystique.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
require "mystique/version"
|
2
2
|
|
3
3
|
require "callable"
|
4
|
-
require "string_plus"
|
5
4
|
|
6
5
|
require "mystique/undefined"
|
6
|
+
require "mystique/presenter_class"
|
7
7
|
require "mystique/presenter"
|
8
8
|
|
9
9
|
module Mystique
|
10
|
-
module_function
|
11
10
|
|
12
|
-
def present(object, with: nil, context: nil, &block)
|
11
|
+
def self.present(object, with: nil, context: nil, &block)
|
13
12
|
begin
|
14
|
-
presenter_class =
|
13
|
+
presenter_class = PresenterClass.new(object, with).to_class
|
15
14
|
presenter_class.for(object, context, &block)
|
16
15
|
rescue NameError
|
17
16
|
return object
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
|
-
def present_collection(collection, context: nil, &block)
|
22
|
-
return to_enum(:present_collection, collection, context: context, &block) unless block_given?
|
20
|
+
def self.present_collection(collection, context: nil, with: nil, &block)
|
21
|
+
return to_enum(:present_collection, collection, context: context, with: with, &block) unless block_given?
|
23
22
|
|
24
23
|
collection.each do |element|
|
25
24
|
case block.arity
|
26
25
|
when 2
|
27
|
-
block.call( present(element, context: context), element )
|
26
|
+
block.call( present(element, context: context, with: with), element )
|
28
27
|
else
|
29
|
-
block.call(present(element, context: context))
|
28
|
+
block.call(present(element, context: context, with: with))
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
|
-
|
35
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.presenter_class_for(object, with)
|
36
|
+
with || Object.send(:const_get, "#{object.class}Presenter")
|
36
37
|
end
|
37
|
-
private :presenter_class_for
|
38
38
|
end
|
data/lib/mystique/presenter.rb
CHANGED
@@ -10,9 +10,9 @@ module Mystique
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.for(object, context=nil)
|
13
|
-
|
13
|
+
new(object, context).tap { |presenter|
|
14
14
|
yield presenter if block_given?
|
15
|
-
|
15
|
+
}
|
16
16
|
end
|
17
17
|
|
18
18
|
def context
|
@@ -21,29 +21,31 @@ module Mystique
|
|
21
21
|
alias :ctx :context
|
22
22
|
alias :h :context
|
23
23
|
|
24
|
-
def
|
24
|
+
def o
|
25
25
|
@__object__
|
26
26
|
end
|
27
27
|
|
28
28
|
def inspect
|
29
|
-
"<#{self.class}(#{
|
29
|
+
"<#{self.class}(#{o.inspect}) context: #{context.inspect}>"
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def method_missing(method, *args, &block)
|
35
|
-
return
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
35
|
+
return o.send(method, *args, &block) if method.to_s.start_with?("to_")
|
36
|
+
|
37
|
+
o.send(method, *args, &block).yield_self { |value|
|
38
|
+
case
|
39
|
+
when formatted_method?(method)
|
40
|
+
format( value )
|
41
|
+
when presented_method?(method)
|
42
|
+
Mystique.present(value, context: context)
|
43
|
+
when presented_collection?(method)
|
44
|
+
Mystique.present_collection(value, context: context, &block)
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
}
|
47
49
|
end
|
48
50
|
|
49
51
|
def formatted_method?(method)
|
@@ -54,16 +56,22 @@ module Mystique
|
|
54
56
|
__presented_methods__.include?(method)
|
55
57
|
end
|
56
58
|
|
59
|
+
def presented_collection?(method)
|
60
|
+
__presented_collections__.include?(method)
|
61
|
+
end
|
62
|
+
|
57
63
|
def format(value)
|
58
|
-
result =
|
64
|
+
result = case
|
65
|
+
when __formats__.keys.include?(value)
|
59
66
|
__formats__[value]
|
60
|
-
|
67
|
+
when __regex_formats__.any? { |regex, _| value =~ regex}
|
61
68
|
__regex_formats__.select { |regex, _| value =~ regex}.first.last
|
62
|
-
|
69
|
+
when __class_formats__.any? { |klass, _| value.is_a?(klass)}
|
63
70
|
__class_formats__.select { |klass, _| value.is_a?(klass)}.first.last
|
64
71
|
else
|
65
72
|
value
|
66
73
|
end
|
74
|
+
|
67
75
|
Mystique.present(Callable(result).call(value, context))
|
68
76
|
end
|
69
77
|
|
@@ -88,6 +96,12 @@ module Mystique
|
|
88
96
|
end
|
89
97
|
end
|
90
98
|
|
99
|
+
def self.present_collection(matcher)
|
100
|
+
if matcher.is_a?(Symbol)
|
101
|
+
__presented_collections__ << matcher
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
91
105
|
def self.format_and_present(matcher)
|
92
106
|
format_method(method)
|
93
107
|
present_method(method)
|
@@ -97,6 +111,10 @@ module Mystique
|
|
97
111
|
@__presented_methods__ ||= []
|
98
112
|
end
|
99
113
|
|
114
|
+
def self.__presented_collections__
|
115
|
+
@__presented_collections__ ||= []
|
116
|
+
end
|
117
|
+
|
100
118
|
def self.__formatted_methods__
|
101
119
|
@__formatted_methods__ ||= []
|
102
120
|
end
|
@@ -105,6 +123,10 @@ module Mystique
|
|
105
123
|
self.class.__presented_methods__
|
106
124
|
end
|
107
125
|
|
126
|
+
def __presented_collections__
|
127
|
+
self.class.__presented_collections__
|
128
|
+
end
|
129
|
+
|
108
130
|
def __formatted_methods__
|
109
131
|
self.class.__formatted_methods__
|
110
132
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mystique
|
2
|
+
class PresenterClass
|
3
|
+
def initialize(object, with=nil)
|
4
|
+
@with = with
|
5
|
+
@object = object
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_class
|
9
|
+
with || Object.send(:const_get, class_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def class_name
|
13
|
+
return with.to_s if with
|
14
|
+
|
15
|
+
"#{base_class_name(object)}Presenter"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :with
|
21
|
+
attr_reader :object
|
22
|
+
|
23
|
+
def base_class_name(for_object)
|
24
|
+
case for_object
|
25
|
+
when Symbol, String
|
26
|
+
for_object.to_s.split(/_/).map(&:capitalize).join
|
27
|
+
when Array
|
28
|
+
for_object.map { |current_object|
|
29
|
+
base_class_name(current_object)
|
30
|
+
}.join("::")
|
31
|
+
else
|
32
|
+
for_object.class.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/mystique/version.rb
CHANGED
data/mystique.gemspec
CHANGED
@@ -19,10 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_development_dependency "bundler", "~> 1.
|
23
|
-
spec.add_development_dependency "rake", "
|
22
|
+
spec.add_development_dependency "bundler", "~> 2.1.4"
|
23
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
24
24
|
spec.add_development_dependency "rspec"
|
25
25
|
spec.add_development_dependency "pry-byebug"
|
26
26
|
spec.add_runtime_dependency "callable"
|
27
|
-
spec.add_runtime_dependency "string_plus"
|
28
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mystique
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Federico Iachetti
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.1.4
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.1.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 12.3.3
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 12.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: string_plus
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
83
|
description: Put a presenter in front of your objects.
|
98
84
|
email:
|
99
85
|
- iachetti.federico@gmail.com
|
@@ -113,6 +99,7 @@ files:
|
|
113
99
|
- lib/mystique.rb
|
114
100
|
- lib/mystique/null_context.rb
|
115
101
|
- lib/mystique/presenter.rb
|
102
|
+
- lib/mystique/presenter_class.rb
|
116
103
|
- lib/mystique/presenters.rb
|
117
104
|
- lib/mystique/presenters/hash_presenter.rb
|
118
105
|
- lib/mystique/undefined.rb
|
@@ -122,7 +109,7 @@ homepage: https://github.com/iachettifederico/mystique
|
|
122
109
|
licenses:
|
123
110
|
- MIT
|
124
111
|
metadata: {}
|
125
|
-
post_install_message:
|
112
|
+
post_install_message:
|
126
113
|
rdoc_options: []
|
127
114
|
require_paths:
|
128
115
|
- lib
|
@@ -137,8 +124,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
124
|
- !ruby/object:Gem::Version
|
138
125
|
version: '0'
|
139
126
|
requirements: []
|
140
|
-
rubygems_version: 3.0.
|
141
|
-
signing_key:
|
127
|
+
rubygems_version: 3.0.8
|
128
|
+
signing_key:
|
142
129
|
specification_version: 4
|
143
130
|
summary: Ruby presenter gem.
|
144
131
|
test_files: []
|