exposant 0.1.2 → 0.2.0

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: e71f97dbf32080d25a520091a6e33d480ad18e6a3fff6bcd6e450b80c0cd5414
4
- data.tar.gz: 499db0ccd9fd33e879dcc035f4decf21ea7c8874042ddc113bc4862b3bf726e6
3
+ metadata.gz: 3b348ab3f3c0d4c3d274469598cd72c5d234d9a832348ec4824fbfc8936a5957
4
+ data.tar.gz: 94ee91f4ae16555a4161e22f4075d2f83293f72af04f5f0c834e9a351634c072
5
5
  SHA512:
6
- metadata.gz: d446462784d85f9b13426e79fb69a484a827c8bb347d117c286fa3da0a841aace9c51ea265a5d23256a53da36112c6b3b6c28be0a6502a28cb1c7414bd80a2e7
7
- data.tar.gz: 4f0642a4b7001c14b149deaf738738ae13e8541cb54c3987405e383ef5656c1ade8fe84c1b8c31756659c7816869c10b0a83023f18500ac73c81d2560d733ed6
6
+ metadata.gz: b51a4907d36637a6d86d209b9577539a2e21ae8cc7c0bdd72c17395927acfe26981e19e7503d04de0677f7036609fadecada2c6ded173cb9d85492144748c842
7
+ data.tar.gz: 467b366ac5b9c5ea8f6a60f4bf3e55a32d5049c3b89c1be222836df651a6b7e12194fe5c5160df38c1855507473d9f8328fae896e3eb0685f82b5db5ec1fa3cb
data/.rubocop.yml CHANGED
@@ -19,7 +19,7 @@ Lint/EmptyClass:
19
19
  Enabled: false
20
20
 
21
21
  Metrics/AbcSize:
22
- Max: 50
22
+ Max: 55
23
23
 
24
24
  Metrics/CyclomaticComplexity:
25
25
  Max: 15
data/Gemfile CHANGED
@@ -10,3 +10,5 @@ gem 'rake', '~> 13.0'
10
10
  gem 'minitest', '~> 5.0'
11
11
 
12
12
  gem 'rubocop', '~> 1.21'
13
+
14
+ gem 'pry'
data/Gemfile.lock CHANGED
@@ -1,29 +1,45 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- exposant (0.1.2)
5
- activemodel (~> 7.0)
6
- activesupport (~> 7.0)
4
+ exposant (0.2.0)
5
+ activemodel (> 5.0)
6
+ activesupport (> 5.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (7.0.4.2)
12
- activesupport (= 7.0.4.2)
13
- activesupport (7.0.4.2)
11
+ activemodel (7.1.1)
12
+ activesupport (= 7.1.1)
13
+ activesupport (7.1.1)
14
+ base64
15
+ bigdecimal
14
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ connection_pool (>= 2.2.5)
18
+ drb
15
19
  i18n (>= 1.6, < 2)
16
20
  minitest (>= 5.1)
21
+ mutex_m
17
22
  tzinfo (~> 2.0)
18
23
  ast (2.4.2)
19
- concurrent-ruby (1.2.0)
20
- i18n (1.12.0)
24
+ base64 (0.1.1)
25
+ bigdecimal (3.1.4)
26
+ coderay (1.1.3)
27
+ concurrent-ruby (1.2.2)
28
+ connection_pool (2.4.1)
29
+ drb (2.1.1)
30
+ ruby2_keywords
31
+ i18n (1.14.1)
21
32
  concurrent-ruby (~> 1.0)
22
33
  json (2.6.1)
34
+ method_source (1.0.0)
23
35
  minitest (5.16.3)
36
+ mutex_m (0.1.2)
24
37
  parallel (1.22.1)
25
38
  parser (3.1.2.1)
26
39
  ast (~> 2.4.1)
40
+ pry (0.14.2)
41
+ coderay (~> 1.1)
42
+ method_source (~> 1.0)
27
43
  rainbow (3.1.1)
28
44
  rake (13.0.6)
29
45
  regexp_parser (2.5.0)
@@ -41,6 +57,7 @@ GEM
41
57
  rubocop-ast (1.21.0)
42
58
  parser (>= 3.1.1.0)
43
59
  ruby-progressbar (1.11.0)
60
+ ruby2_keywords (0.0.5)
44
61
  tzinfo (2.0.6)
45
62
  concurrent-ruby (~> 1.0)
46
63
  unicode-display_width (2.2.0)
@@ -51,6 +68,7 @@ PLATFORMS
51
68
  DEPENDENCIES
52
69
  exposant!
53
70
  minitest (~> 5.0)
71
+ pry
54
72
  rake (~> 13.0)
55
73
  rubocop (~> 1.21)
56
74
 
data/README.md CHANGED
@@ -2,9 +2,14 @@
2
2
 
3
3
  In a Rails application, it is often required to fill a gap between Models and
4
4
  Views. There are of course, many differents ways to fill this gap, one of these
5
- is exhibitors (or improved decorators).
5
+ is decorators and its variants exhibits or presenters.
6
6
 
7
- This gem provide an easy way to create Ruby exhibitors or decorators.
7
+ The main difference between decorators, exhibits and presenters are their
8
+ proximity with the rendering layer. Typically a decorator is not meant to be
9
+ contextualized, whereas an exhibit is intended to have access to rendering
10
+ context.
11
+
12
+ This gem provide an easy way to create theese concepts in Ruby.
8
13
 
9
14
  ## Installation
10
15
 
@@ -16,74 +21,90 @@ gem 'exposant'
16
21
 
17
22
  And then execute:
18
23
 
19
- $ bundle install
24
+ ```ruby
25
+ $ bundle install
26
+ ```
20
27
 
21
28
  Or install it yourself as:
22
29
 
23
- $ gem install exposant
30
+ ```
31
+ $ gem install exposant
32
+ ```
24
33
 
25
34
  ## Usage
26
35
 
27
- There are two kinds of exhibitors refering to model or collection.
28
-
29
- A collection exhibitor is meant to encapsulate an enumerable object (like
30
- ActiveRecord Relation or just Array). It overrides `each` method to ensure
31
- encapsulation of resulting objects.
36
+ Exposant objects are intended to overload class (scopes) and instance methods
37
+ of any other object. The default type is exposant, choosing between decorator,
38
+ exhibit or any other type name is up to you. There is no magic involved for the
39
+ context, you just have to call contextualize and provide the required context.
32
40
 
33
- A model exhibitor improve it's associated object, like adding non-database
34
- related methods to an ActiveRecord object for example.
35
-
36
- To use this gem in a Rails application, create a folder `app/exhibitors`.
37
- Create pluralized exhibitors for collections and singularized exhibitors for
38
- models.
39
-
40
- ### Example:
41
+ ### Basic example
41
42
 
42
43
  Consider having a User model with `first_name` and `last_name`
43
44
 
44
45
  ```ruby
45
- # app/models/application_record.rb
46
- class ApplicationRecord < ActiveRecord::Base
47
- include Exposant::Exposable
46
+ # app/models/user.rb
47
+ class User < ActiveRecord::Base
48
+ include Exposant::Model
49
+ has_exposant type: :decorator
48
50
  end
49
51
 
50
- # app/exhibitors/user_exhibitor.rb
51
- class UserExhibitor < Exposant::ModelExhibitor
52
+ # app/decorators/user_decorator.rb
53
+ class UserDecorator < Exposant::Base
54
+ exposant_type :decorator
55
+
52
56
  def full_name
53
57
  "#{first_name} #{last_name}"
54
58
  end
55
59
  end
60
+ ```
61
+
62
+ Then you may want to use your brand new decorator in your controller
56
63
 
57
- # app/exhibitors/users_exhibitor.rb
58
- class UsersExhibitor < Exposant::CollectionExhibitor
59
- # You can add methods for collections too if necessary
64
+ ```ruby
65
+ # app/controllers/users_controller.rb
66
+ class UsersController < DefaultController
67
+ def index
68
+ @users = User.decorator(User.all)
69
+ end
70
+
71
+ def show
72
+ @user = User.find(...).decorator
73
+ end
60
74
  end
61
75
  ```
62
76
 
63
- Then you may want to use your brand new exhibitor in your controller
77
+ ### Contextualization example
78
+
79
+ If you want to contextualize a presenter, for example in a Rails application.
80
+
64
81
  ```ruby
65
82
  # app/controllers/users_controller.rb
66
83
  class UsersController < DefaultController
67
84
  def index
68
- @users = User.exhibitor(User.all)
85
+ @users = User.presenter(User.all)
86
+ @users.contextualize(self)
69
87
  end
70
88
 
71
89
  def show
72
- @user = User.find(...).exhibitor
90
+ @user = User.find(...).presenter
91
+ @user.contextualize(self)
73
92
  end
74
93
  end
75
94
  ```
76
95
 
77
96
  ## Development
78
97
 
79
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
80
-
81
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
98
+ After checking out the repo, run `bin/setup` to install dependencies. You can
99
+ also run `bin/console` for an interactive prompt that will allow you to
100
+ experiment.
82
101
 
83
102
  ## Contributing
84
103
 
85
- Bug reports and pull requests are welcome on GitHub at https://github.com/kmmndr/exposant.
104
+ Bug reports and pull requests are welcome on GitHub at
105
+ https://github.com/kmmndr/exposant.
86
106
 
87
107
  ## License
88
108
 
89
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
109
+ The gem is available as open source under the terms of the
110
+ [MIT License](https://opensource.org/licenses/MIT).
data/exposant.gemspec CHANGED
@@ -30,9 +30,8 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- # Uncomment to register a new dependency of your gem
34
- spec.add_dependency 'activemodel', '~> 7.0'
35
- spec.add_dependency 'activesupport', '~> 7.0'
33
+ spec.add_dependency 'activemodel', '> 5.0'
34
+ spec.add_dependency 'activesupport', '> 5.0'
36
35
 
37
36
  # For more information and examples about making a new gem, check out our
38
37
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -0,0 +1,92 @@
1
+ module Exposant
2
+ class Base < SimpleDelegator
3
+ include Exposant::Contextualizable
4
+ extend ActiveModel::Naming
5
+
6
+ def initialize(*)
7
+ super
8
+
9
+ extend(Exposant::Collection) if __getobj__.is_a?(Enumerable)
10
+ end
11
+
12
+ def to_model
13
+ __getobj__
14
+ end
15
+
16
+ def self.respond_to_missing?(name, *)
17
+ klass.respond_to?(name) || super
18
+ end
19
+
20
+ def self.method_missing(name, *args, &block)
21
+ klass.send(name, *args, &block)
22
+ end
23
+
24
+ def self.human_attribute_name(*args)
25
+ exposed_class.human_attribute_name(*args)
26
+ end
27
+
28
+ def self.klass
29
+ @klass ||= exposed_class
30
+ end
31
+
32
+ def self.belongs_to_model(name)
33
+ exposed_class(name)
34
+ end
35
+
36
+ def self.exposed_class(value = nil)
37
+ @exposed_class = value.constantize if value.present?
38
+ return @exposed_class if @exposed_class.present?
39
+
40
+ return ancestors[1].exposed_class unless ancestors[1] == Exposant::Base || ancestors[1].exposant_base?
41
+
42
+ klass_name = name.gsub(/#{type_name}$/, '')
43
+
44
+ klass_name.constantize
45
+ end
46
+
47
+ def self.exposant_type(value = nil)
48
+ @exposant_type = value if value.present?
49
+ return @exposant_type if @exposant_type.present?
50
+
51
+ return ancestors[1].exposant_type unless ancestors[1] == Exposant::Base
52
+
53
+ :exposant
54
+ end
55
+
56
+ def self.type_name
57
+ exposant_type.to_s.camelcase
58
+ end
59
+
60
+ def self.custom_type?
61
+ exposant_type != :exposant
62
+ end
63
+
64
+ def self.exposant_base?
65
+ !!@exposant_base
66
+ end
67
+
68
+ def self.exposant_base
69
+ @exposant_base = true
70
+ end
71
+
72
+ def self.exposant_variant
73
+ exposed_name = exposed_class.name.demodulize
74
+
75
+ variant = name
76
+ .split('::')
77
+ .tap { |arr| arr.last.gsub!(/#{exposed_name}#{type_name}$/, '') }
78
+ .last
79
+ .downcase
80
+
81
+ return nil if variant.blank?
82
+
83
+ variant.to_sym
84
+ end
85
+
86
+ def self.parent_exposant
87
+ return ancestors[1].parent_exposant unless ancestors[1] == Exposant::Base
88
+
89
+ name.constantize
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,16 @@
1
+ module Exposant
2
+ module Collection
3
+ include Enumerable
4
+
5
+ def each
6
+ return enum_for(:each) unless block_given?
7
+
8
+ super do |obj|
9
+ exposant = obj.exposant(self.class.exposant_variant, self.class.exposant_type)
10
+ exposant.contextualize(context) if contextualized?
11
+
12
+ yield exposant
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module Exposant
2
+ module Contextualizable
3
+ attr_accessor :context
4
+
5
+ def contextualize(context)
6
+ self.context = context
7
+ end
8
+
9
+ def contextualized?
10
+ context.present?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,82 @@
1
+ require 'pry'
2
+ module Exposant
3
+ module Model
4
+ extend ActiveSupport::Concern
5
+
6
+ def exposant(variant = nil, type = nil)
7
+ self.class.exposant_class(variant, type).new(self)
8
+ end
9
+
10
+ module ClassMethods
11
+ def has_exposant(name: nil, type: nil)
12
+ @exposant_class = name
13
+ @exposant_type = type
14
+
15
+ if type.present? && type != :exposant
16
+ raise 'Type must be a symbol' unless type.is_a?(Symbol)
17
+
18
+ define_method type do |variant = nil|
19
+ exposant(variant, type)
20
+ end
21
+
22
+ define_singleton_method type do |obj, variant = nil|
23
+ exposant(obj, variant, type)
24
+ end
25
+ end
26
+
27
+ self
28
+ end
29
+
30
+ def exposant_type
31
+ @exposant_type || :exposant
32
+ end
33
+
34
+ def exposant(obj, variant = nil, type = nil)
35
+ obj.extend(ExposantMethods)
36
+ obj.model_klass = self
37
+
38
+ if type.present? && type != :exposant
39
+ raise 'Type must be a symbol' unless type.is_a?(Symbol)
40
+
41
+ obj.singleton_class.class_eval do
42
+ define_method type do |var = nil|
43
+ exposant(var, type)
44
+ end
45
+ end
46
+ end
47
+
48
+ obj.exposant(variant, type)
49
+ end
50
+
51
+ def exposant_class(variant = nil, type = nil)
52
+ type_name = (type || exposant_type).to_s.camelcase
53
+ klass = if @exposant_class.present?
54
+ @exposant_class
55
+ else
56
+ name.dup.concat(type_name)
57
+ end
58
+
59
+ klass = klass
60
+ .split('::')
61
+ .tap { |arr| arr.last.prepend(variant&.to_s&.downcase&.capitalize || '') }
62
+ .join('::')
63
+
64
+ raise "Missing exposant #{klass}" unless const_defined?(klass)
65
+
66
+ klass.constantize
67
+ end
68
+ end
69
+ end
70
+
71
+ module ExposantMethods
72
+ attr_accessor :model_klass
73
+
74
+ def exposant(variant = nil, type = nil)
75
+ exposant_class(variant, type).new(self)
76
+ end
77
+
78
+ def exposant_class(variant = nil, type = nil)
79
+ model_klass.exposant_class(variant, type)
80
+ end
81
+ end
82
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exposant
4
- VERSION = '0.1.2'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/exposant.rb CHANGED
@@ -4,13 +4,12 @@ require 'delegate'
4
4
  require 'active_support'
5
5
  require 'active_model'
6
6
 
7
- require_relative 'exposant/concerns/exhibitor'
8
- require_relative 'exposant/concerns/exposable'
9
- require_relative 'exposant/collection_exhibitor'
10
- require_relative 'exposant/model_exhibitor'
7
+ require_relative 'exposant/concerns/contextualizable'
8
+ require_relative 'exposant/concerns/collection'
9
+ require_relative 'exposant/model'
10
+ require_relative 'exposant/base'
11
11
  require_relative 'exposant/version'
12
12
 
13
13
  module Exposant
14
14
  class Error < StandardError; end
15
- # Your code goes here...
16
15
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exposant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Kienlen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-10 00:00:00.000000000 Z
11
+ date: 2023-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: '7.0'
19
+ version: '5.0'
20
20
  type: :runtime
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: '7.0'
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.0'
33
+ version: '5.0'
34
34
  type: :runtime
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: '7.0'
40
+ version: '5.0'
41
41
  description:
42
42
  email:
43
43
  - kommander@laposte.net
@@ -54,10 +54,10 @@ files:
54
54
  - Rakefile
55
55
  - exposant.gemspec
56
56
  - lib/exposant.rb
57
- - lib/exposant/collection_exhibitor.rb
58
- - lib/exposant/concerns/exhibitor.rb
59
- - lib/exposant/concerns/exposable.rb
60
- - lib/exposant/model_exhibitor.rb
57
+ - lib/exposant/base.rb
58
+ - lib/exposant/concerns/collection.rb
59
+ - lib/exposant/concerns/contextualizable.rb
60
+ - lib/exposant/model.rb
61
61
  - lib/exposant/version.rb
62
62
  homepage: http://127.0.0.1:3000
63
63
  licenses:
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  requirements: []
83
- rubygems_version: 3.3.7
83
+ rubygems_version: 3.4.10
84
84
  signing_key:
85
85
  specification_version: 4
86
86
  summary: Simple way to create decorators and presenters
@@ -1,26 +0,0 @@
1
- module Exposant
2
- class CollectionExhibitor < SimpleDelegator
3
- include Exhibitor
4
- extend ActiveModel::Naming
5
- include Enumerable
6
-
7
- def self.exhibitor_variant
8
- self::MODEL_PRESENTER_VARIANT if const_defined?('MODEL_PRESENTER_VARIANT')
9
- end
10
-
11
- def each
12
- return enum_for(:each) unless block_given?
13
-
14
- __getobj__.each do |o|
15
- exh = o&.exhibitor(self.class.exhibitor_variant)
16
- exh.contextualize(context) if exh.present? && contextualized?
17
-
18
- yield exh
19
- end
20
- end
21
-
22
- def to_model
23
- self
24
- end
25
- end
26
- end
@@ -1,34 +0,0 @@
1
- module Exhibitor
2
- extend ActiveSupport::Concern
3
- attr_accessor :context
4
-
5
- def obj
6
- __getobj__
7
- end
8
-
9
- def exhibitor_for(obj)
10
- self.class.exhibitor_for(obj)
11
- end
12
-
13
- def contextualize(context)
14
- self.context = context
15
- end
16
-
17
- def contextualized?
18
- context.present?
19
- end
20
-
21
- module ClassMethods
22
-
23
- def exhibitor_for_super(method, klass = nil)
24
- define_method(method) do |*args|
25
- klass ||= self.class
26
- klass.new(super(*args))
27
- end
28
- end
29
-
30
- def exhibitor_for(obj)
31
- new(obj)
32
- end
33
- end
34
- end
@@ -1,56 +0,0 @@
1
- module Exposant
2
- module Exposable
3
- module Model
4
- extend ActiveSupport::Concern
5
-
6
- def exhibitor(variant = nil)
7
- self.class.exhibitor_class(variant).new(self)
8
- end
9
-
10
- module ClassMethods
11
- def exhibitor(obj, variant = nil)
12
- obj.extend(Exposable::Collection)
13
- obj.model_klass = self
14
-
15
- obj.exhibitor(variant)
16
- end
17
-
18
- def exhibitor_class(variant = nil)
19
- klass = [
20
- name,
21
- variant&.downcase&.capitalize,
22
- 'Exhibitor'
23
- ].join
24
-
25
- raise "Missing exhibitor #{klass}" unless const_defined?(klass)
26
-
27
- klass.constantize
28
- end
29
- end
30
- end
31
-
32
- module Collection
33
- attr_accessor :model_klass
34
-
35
- def exhibitor(variant = nil)
36
- exhibitor_class(variant).new(self)
37
- end
38
-
39
- def exhibitor_class(variant = nil)
40
- klass_name = model_klass.name
41
-
42
- klass = [
43
- klass_name.pluralize,
44
- variant&.downcase&.capitalize,
45
- 'Exhibitor'
46
- ].join
47
-
48
- begin
49
- klass.constantize
50
- rescue NameError
51
- raise "Missing exhibitor #{klass}"
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,34 +0,0 @@
1
- module Exposant
2
- class ModelExhibitor < SimpleDelegator
3
- include Exhibitor
4
- extend ActiveModel::Naming
5
-
6
- def to_model
7
- obj
8
- end
9
-
10
- def self.human_attribute_name(*args)
11
- exhibited_class.human_attribute_name(*args)
12
- end
13
-
14
- def self.exhibited_class
15
- return ancestors[1].exhibited_class unless ancestors[1] == ModelExhibitor
16
-
17
- name.gsub(/Exhibitor$/, '').constantize
18
- end
19
-
20
- def self.exhibitor_variant
21
- variant = name[parent_exhibitor.exhibited_class.name.length..].gsub(/Exhibitor$/, '').downcase
22
-
23
- return nil if variant.blank?
24
-
25
- variant.to_sym
26
- end
27
-
28
- def self.parent_exhibitor
29
- return ancestors[1].parent_exhibitor unless ancestors[1] == ModelExhibitor
30
-
31
- name.constantize
32
- end
33
- end
34
- end