mystique 0.9.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2ab3b70d916e56b8cce430379cf148e049ad2681931f5ed0f81eaa089f2fc86
4
- data.tar.gz: 9785cc05e6ef78b7228ff97da5b11d303f6ff2053ac7a124ee69f6b15e021516
3
+ metadata.gz: 02f8184f7dc42d547bf1a953219e7fc4fbb441a6bc435370a48bd971b218cd8d
4
+ data.tar.gz: 3e379ef4b394972fc13598a585bcfa8a182e5b1ea62fb33719fba79a37f2caf1
5
5
  SHA512:
6
- metadata.gz: c85c86ccea8b6a7178a3dc18a17e0cdad8663be3d0861e3ae6043cd1e8ec1e5479a327ca672bb60785f42dbab313b8fe475daaa776dda06186a63e3015aebd26
7
- data.tar.gz: 6e30f16fb9fcf8867a8a285c5c54bbdc4f865ea4ef0eea014a3927cff130f4cbde4d016b92f6e424291db02ddf64df88365d4ac4eda7f79ef16cd3bbb7b361fe
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, or returns it. If there default presenter is not available, the original object gets yielded/returned.
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 target object will be rendered.
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
- class UserPresenter < Mystique::Presenter
42
- context MyHelpers
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 `MyHelpers` module as the context for any instance of `UserPresenter`
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(some_user, context: MyHelpers)
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 a `format` method that allows you to define defaults for some response types.
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 every case, `format` will accept a value or a block to return, which will yield the found value and the context.
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 nil, "N/A"
103
+ format :price
104
+
105
+ apply_format nil, "N/A"
79
106
  end
80
107
 
81
- item_presenter.price
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
- format Float do |value, context|
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 /\w+@\w+\.\w+/ do |email, context|
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
- Mystique.present(Item.new("Wine", 50, 42.3)) do |presenter|
134
- presenter.class
135
- # => ItemPresenter
175
+ require "time"
136
176
 
137
- presenter.price
138
- # => "$ 50.00"
177
+ User = Struct.new(:last_log_in)
139
178
 
140
- presenter.list_price
141
- # => "$ 42.30"
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
@@ -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 = presenter_class_for(object, with)
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
- def presenter_class_for(object, with)
35
- with || StringPlus.constantize("#{object.class}Presenter")
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
@@ -10,9 +10,9 @@ module Mystique
10
10
  end
11
11
 
12
12
  def self.for(object, context=nil)
13
- self.new(object, context).tap do |presenter|
13
+ new(object, context).tap { |presenter|
14
14
  yield presenter if block_given?
15
- end
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 target
24
+ def o
25
25
  @__object__
26
26
  end
27
27
 
28
28
  def inspect
29
- "<#{self.class}(#{target.inspect}) context: #{context.inspect}>"
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 target.send(method, *args, &block) if method.to_s.start_with?("to_")
36
-
37
- value = target.send(method, *args, &block)
38
-
39
- case
40
- when formatted_method?(method)
41
- format( value )
42
- when presented_method?(method)
43
- Mystique.present(value, context: context)
44
- else
45
- value
46
- end
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 = if __formats__.keys.include?(value)
64
+ result = case
65
+ when __formats__.keys.include?(value)
59
66
  __formats__[value]
60
- elsif __regex_formats__.any? { |regex, _| value =~ regex}
67
+ when __regex_formats__.any? { |regex, _| value =~ regex}
61
68
  __regex_formats__.select { |regex, _| value =~ regex}.first.last
62
- elsif __class_formats__.any? { |klass, _| value.is_a?(klass)}
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
@@ -1,3 +1,3 @@
1
1
  module Mystique
2
- VERSION = "0.9.1"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -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.8"
23
- spec.add_development_dependency "rake", "~> 10.0"
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.9.1
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: 2019-05-10 00:00:00.000000000 Z
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: '1.8'
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: '1.8'
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: '10.0'
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: '10.0'
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.1
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: []