magic-presenter 0.1.0 → 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: c2d9f852b05ac3df9f02d0a6f43256155d36f0aa54c9b94887017c6695040000
4
- data.tar.gz: 07f21527902b18f58d4ffc88655b3e37317a331fa8db2f37addaa421478a523b
3
+ metadata.gz: 04a88e0f222913a774946299ef036231cb1628baaa980111b5bb058cb77f69a4
4
+ data.tar.gz: 9a5d28343913ebae389a941153d49d6c3d04acb2e6e61891ada49404a2e1d49f
5
5
  SHA512:
6
- metadata.gz: 3d230e25c5b5a5bfaef1e941df5388cdcc71315287fbf71177fa7ebe1ca13ff4fa16a2e6a07e358bbed35213053262e6900b390cdc9572f5e33ea5ae59161626
7
- data.tar.gz: 36e3545b509b62c1c68f22d156adec1ef46ddf34ff0efeb9875aedf13bac1856a6387006211ad9c93a9dc118aa55f98a6a0db09133172d8b6453ed6f81e968e1
6
+ metadata.gz: 0a572d9c94e5b75cb65c23e029d524f19d48457d1ea57bf6185d4ed463757296c2917d77e7210ab67021347b111136e34c1cbcdb15ae47c6d67445623ff13508
7
+ data.tar.gz: 41c4b6afee8ffb1b89aedbba4f619d94ddc04d3c4201afa6ae7c34fec7d1fe52a746eb3fc29463d316fc446c4e1a7b9458395c473c18af02b388caae0f2dabaa
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # 🧙 Magic Presenter
2
2
 
3
+ ![GitHub Actions Workflow Status](
4
+ https://img.shields.io/github/actions/workflow/status/Alexander-Senko/magic-presenter/ci.yml
5
+ )
3
6
  ![Code Climate maintainability](
4
7
  https://img.shields.io/codeclimate/maintainability-percentage/Alexander-Senko/magic-presenter
5
8
  )
@@ -15,11 +18,15 @@ Based on [Magic Decorator](https://github.com/Alexander-Senko/magic-decorator),
15
18
 
16
19
  Install the gem and add to the application's Gemfile by executing:
17
20
 
18
- $ bundle add magic-presenter
21
+ $ bundle add magic-presenter
19
22
 
20
23
  If bundler is not being used to manage dependencies, install the gem by executing:
21
24
 
22
- $ gem install magic-presenter
25
+ $ gem install magic-presenter
26
+
27
+ After all the gems are `bundle`d run the installer in the project directory to generate the necessary files:
28
+
29
+ $ bin/rails generate magic:presenter:install
23
30
 
24
31
  ## Usage
25
32
 
@@ -51,7 +58,17 @@ When no presenter is found,
51
58
  - `#decorate!` raises `Magic::Lookup::Error`,
52
59
  - `#decorated` returns the original object.
53
60
 
54
- ## Magic
61
+ ### Generators
62
+
63
+ A generator can be used to generate a presenter:
64
+
65
+ $ bin/rails generate presenter Person
66
+
67
+ See the help for more info:
68
+
69
+ $ bin/rails generate presenter --help
70
+
71
+ ## 🧙 Magic
55
72
 
56
73
  It’s based on [Magic Decorator](
57
74
  https://github.com/Alexander-Senko/magic-decorator#magic
@@ -59,7 +76,7 @@ It’s based on [Magic Decorator](
59
76
 
60
77
  ### Presentable scope
61
78
 
62
- `Magic::Presentable` is mixed into `ActiveModel::Model` by default.
79
+ `Magic::Presentable` is mixed into `ActiveModel::API` by default.
63
80
  It means that any model, be it `ActiveRecord::Base`, `Mongoid::Document` or whatever else, is _magically presentable_.
64
81
 
65
82
  ### Presenter class inference
@@ -68,9 +85,24 @@ Presenters provide automatic class inference for any model based on its class na
68
85
  https://github.com/Alexander-Senko/magic-lookup
69
86
  ).
70
87
 
71
- For example, `MyNamespace::MyModel.new.decorate` looks for `MyNamespace::MyModelPresenter` first.
88
+ For example, `MyNamespace::MyModel.new.decorate` looks for `MyNamespace::MyPresenter` first.
72
89
  When missing, it further looks for decorators for its ancestor classes, up to `ObjectPresenter`.
73
90
 
91
+ #### Mapping rules
92
+
93
+ - `MyObject` → `MyObjectPresenter`
94
+ - `MyModel` → `MyPresenter`
95
+ - `MyRecord` → `MyPresenter`
96
+
97
+ > [!TIP]
98
+ > That’s why `ApplicationPresenter` presents `ApplicationRecord` alongside all its descendants automagically with no extra code.
99
+
100
+ When in doubt, one can use `Magic::Presenter.name_for`:
101
+
102
+ ```ruby
103
+ Magic::Presenter.name_for Person # => "PersonPresenter"
104
+ ```
105
+
74
106
  ## Development
75
107
 
76
108
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.to_prepare do
4
+ [ Rails.root / 'app/presenters' ]
5
+ .select(&:exist?)
6
+ .each { Rails.autoloaders.main.eager_load_dir _1 }
7
+ end unless Rails.application.config.eager_load
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- ActiveSupport.on_load :active_model do
4
- include Magic::Presentable
3
+ Rails.application.config.to_prepare do
4
+ ActiveModel::API.include Magic::Presentable
5
5
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ config.include concern(:PresenterExampleGroup) {
5
+ included { metadata[:type] = :presenter }
6
+ }, file_path: %r'spec/presenters', type: :presenter
7
+ end if defined? RSpec
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magic
4
+ module Presenter
5
+ module Generator # :nodoc:
6
+ require 'generators/presenter/presenter_generator'
7
+
8
+ private
9
+
10
+ def file_name name = super()
11
+ name
12
+ .camelize
13
+ .then { Magic::Presenter.name_for _1 }
14
+ .underscore
15
+ end
16
+
17
+ def file_path path = super(), root: target_root
18
+ root / 'presenters' / path
19
+ end
20
+
21
+ def presenter_path(*) = file_path(*, root: PresenterGenerator.target_root)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ Description:
2
+ Generates application files used by Magic Presenter:
3
+ ApplicationPresenter: a base class for other presenters to
4
+ inherit from.
5
+
6
+ Example:
7
+ bin/rails generate magic:presenter:install
8
+
9
+ This will create:
10
+ ApplicationPresenter: app/presenters/application_presenter.rb
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magic
4
+ module Presenter
5
+ class InstallGenerator < Rails::Generators::Base # :nodoc:
6
+ include Generator
7
+
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ def create_files
11
+ template 'application_presenter.rb', "#{presenter_path namespaced_file_name 'ApplicationRecord'}.rb"
12
+ end
13
+
14
+ private
15
+
16
+ def namespaced_file_name(*)
17
+ File.join *(namespaced_path if namespaced?), file_name(*)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ <% module_namespacing do -%>
2
+ class ApplicationPresenter < Magic::Presenter::Base
3
+ # Define presentation-specific methods here.
4
+ # They are shared by all the descendant presenters.
5
+ end
6
+ <% end -%>
@@ -0,0 +1,28 @@
1
+ Description:
2
+ Generates a new presenter for a model. Pass the model name, either
3
+ CamelCased or under_scored, as an argument.
4
+
5
+ This generator invokes your configured test framework, which
6
+ defaults to TestUnit. It supports both TestUnit and RSpec.
7
+
8
+ If a `--parent` option is given, it’s used as a superclass of the
9
+ created presenter.
10
+
11
+ Example:
12
+ bin/rails generate presenter account
13
+
14
+ This will create:
15
+ Presenter: app/presenters/account_presenter.rb
16
+ for TestUnit:
17
+ Test: test/presenters/account_presenter_test.rb
18
+ for RSpec:
19
+ Spec: spec/presenters/account_presenter_spec.rb
20
+
21
+ bin/rails generate presenter admin/account
22
+
23
+ This will create:
24
+ Presenter: app/presenters/admin/account_presenter.rb
25
+ for TestUnit:
26
+ Test: test/presenters/admin/account_presenter_test.rb
27
+ for RSpec:
28
+ Spec: spec/presenters/admin/account_presenter_spec.rb
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PresenterGenerator < Rails::Generators::NamedBase # :nodoc:
4
+ include Magic::Presenter::Generator
5
+
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ check_class_collision suffix: 'Presenter'
9
+
10
+ class_option :parent,
11
+ type: :string,
12
+ default: 'ApplicationPresenter',
13
+ desc: 'The parent class for the generated presenter'
14
+
15
+ cattr_reader :target_root, default: Pathname('app')
16
+
17
+ def create_presenter_file
18
+ template 'presenter.rb', "#{file_path}.rb"
19
+ end
20
+
21
+ hook_for :test_framework
22
+
23
+ private
24
+
25
+ def parent_class_name = options[:parent].classify
26
+ end
@@ -0,0 +1,5 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < <%= parent_class_name %>
3
+ # Define presentation-specific methods here.
4
+ end
5
+ <% end -%>
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'generators/rspec'
4
+ require 'generators/magic/presenter/generator'
5
+
6
+ module Rspec # :nodoc:
7
+ module Generators # :nodoc:
8
+ class PresenterGenerator < Base # :nodoc:
9
+ include Magic::Presenter::Generator
10
+
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ cattr_reader :target_root, default: Pathname('spec')
14
+
15
+ def create_test_file
16
+ template 'presenter_spec.rb', "#{file_path}_spec.rb"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ <% module_namespacing do -%>
4
+ RSpec.describe <%= class_name %> do
5
+ pending "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ <% end -%>
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/test_unit'
4
+ require 'generators/magic/presenter/generator'
5
+
6
+ module TestUnit # :nodoc:
7
+ module Generators # :nodoc:
8
+ class PresenterGenerator < Base # :nodoc:
9
+ include Magic::Presenter::Generator
10
+
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ check_class_collision suffix: 'PresenterTest'
14
+
15
+ cattr_reader :target_root, default: Pathname('test')
16
+
17
+ def create_test_file
18
+ template 'presenter_test.rb', "#{file_path}_test.rb"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require "test_helper"
2
+
3
+ <% module_namespacing do -%>
4
+ class <%= class_name %>Test < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ <% end -%>
@@ -9,6 +9,6 @@ module Magic
9
9
 
10
10
  private
11
11
 
12
- def decorator = Presenter.for self.class
12
+ def decorator_base = Presenter
13
13
  end
14
14
  end
@@ -13,12 +13,18 @@ module Magic
13
13
  #
14
14
  # Presenters provide automatic class inference for any model based
15
15
  # on its class name powered by Magic Lookup.
16
- # For example, `MyModel.new` looks for `MyModelPresenter` first.
16
+ # For example, `MyModel.new` looks for `MyPresenter` first.
17
17
  # If not found, it looks for presenters of its ancestor classes,
18
18
  # up to `ObjectPresenter`.
19
19
  class Base < Decorator::Base
20
20
  class << self
21
- def name_for(object_class) = "#{object_class}Presenter"
21
+ def name_for object_class
22
+ object_class
23
+ .to_s
24
+ .delete_suffix('Model')
25
+ .delete_suffix('Record')
26
+ .then { "#{_1}Presenter" }
27
+ end
22
28
  end
23
29
  end
24
30
  end
@@ -4,6 +4,10 @@ module Magic
4
4
  module Presenter
5
5
  class Engine < ::Rails::Engine # :nodoc:
6
6
  isolate_namespace Magic::Presenter
7
+
8
+ config.generators do
9
+ _1.test_framework = :rspec
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Magic
4
4
  module Presenter
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -5,12 +5,13 @@ require 'magic/decorator'
5
5
  require_relative 'presenter/version'
6
6
  require_relative 'presenter/engine'
7
7
 
8
- module Magic
8
+ module Magic # :nodoc:
9
9
  autoload :Presentable, 'magic/presentable'
10
10
 
11
11
  # Presentation layer for Rails models
12
12
  module Presenter
13
- autoload :Base, 'magic/presenter/base'
13
+ autoload :Base, 'magic/presenter/base'
14
+ autoload :Generator, 'generators/magic/presenter/generator'
14
15
 
15
16
  module_function
16
17
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magic-presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Senko
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2024-10-19 00:00:00.000000000 Z
10
+ date: 2024-10-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -35,14 +35,14 @@ dependencies:
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: '0'
38
+ version: 0.3.0.alpha
39
39
  type: :runtime
40
40
  prerelease: false
41
41
  version_requirements: !ruby/object:Gem::Requirement
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: 0.3.0.alpha
46
46
  description: Based on Magic Decorator, it’s meant to replace Draper.
47
47
  email:
48
48
  - Alexander.Senko@gmail.com
@@ -53,7 +53,20 @@ files:
53
53
  - MIT-LICENSE
54
54
  - README.md
55
55
  - Rakefile
56
+ - config/initializers/loading.rb
56
57
  - config/initializers/presentable.rb
58
+ - config/initializers/rspec.rb
59
+ - lib/generators/magic/presenter/generator.rb
60
+ - lib/generators/magic/presenter/install/USAGE
61
+ - lib/generators/magic/presenter/install/install_generator.rb
62
+ - lib/generators/magic/presenter/install/templates/application_presenter.rb.tt
63
+ - lib/generators/presenter/USAGE
64
+ - lib/generators/presenter/presenter_generator.rb
65
+ - lib/generators/presenter/templates/presenter.rb.tt
66
+ - lib/generators/rspec/presenter/presenter_generator.rb
67
+ - lib/generators/rspec/presenter/templates/presenter_spec.rb.tt
68
+ - lib/generators/test_unit/presenter/presenter_generator.rb
69
+ - lib/generators/test_unit/presenter/templates/presenter_test.rb.tt
57
70
  - lib/magic/presentable.rb
58
71
  - lib/magic/presenter.rb
59
72
  - lib/magic/presenter/authors.rb
@@ -67,7 +80,7 @@ licenses:
67
80
  metadata:
68
81
  homepage_uri: https://github.com/Alexander-Senko/magic-presenter
69
82
  source_code_uri: https://github.com/Alexander-Senko/magic-presenter
70
- changelog_uri: https://github.com/Alexander-Senko/magic-presenter/blob/v0.1.0/CHANGELOG.md
83
+ changelog_uri: https://github.com/Alexander-Senko/magic-presenter/blob/v0.2.0/CHANGELOG.md
71
84
  rdoc_options: []
72
85
  require_paths:
73
86
  - lib