characterize 0.0.2 → 0.2.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 +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +93 -1
- data/Rakefile +10 -9
- data/lib/characterize/collection.rb +65 -0
- data/lib/characterize/controller.rb +101 -46
- data/lib/characterize/feature_controls.rb +56 -34
- data/lib/characterize/feature_set.rb +19 -0
- data/lib/characterize/object_set.rb +56 -0
- data/lib/characterize/railtie.rb +5 -7
- data/lib/characterize/relation_collection.rb +31 -0
- data/lib/characterize/version.rb +1 -1
- data/lib/characterize/view_forwards.rb +15 -6
- data/lib/characterize.rb +44 -8
- data/lib/generators/characterize/install/install_generator.rb +16 -0
- data/lib/generators/characterize/templates/initializer.rb +9 -0
- metadata +26 -125
- data/.gitignore +0 -18
- data/.ruby-version +0 -1
- data/Gemfile +0 -10
- data/characterize.gemspec +0 -25
- data/test/characterize_test.rb +0 -8
- data/test/internal/README.rdoc +0 -28
- data/test/internal/Rakefile +0 -6
- data/test/internal/app/assets/images/.keep +0 -0
- data/test/internal/app/assets/javascripts/application.js +0 -13
- data/test/internal/app/assets/stylesheets/application.css +0 -15
- data/test/internal/app/characters/special_character.rb +0 -5
- data/test/internal/app/characters/user_character.rb +0 -2
- data/test/internal/app/controllers/application_controller.rb +0 -5
- data/test/internal/app/controllers/concerns/.keep +0 -0
- data/test/internal/app/controllers/users_controller.rb +0 -6
- data/test/internal/app/helpers/application_helper.rb +0 -2
- data/test/internal/app/mailers/.keep +0 -0
- data/test/internal/app/models/.keep +0 -0
- data/test/internal/app/models/concerns/.keep +0 -0
- data/test/internal/app/models/user.rb +0 -2
- data/test/internal/app/views/layouts/application.html.erb +0 -13
- data/test/internal/app/views/users/show.html.erb +0 -2
- data/test/internal/bin/bundle +0 -3
- data/test/internal/bin/rails +0 -4
- data/test/internal/bin/rake +0 -4
- data/test/internal/config/application.rb +0 -29
- data/test/internal/config/boot.rb +0 -5
- data/test/internal/config/database.yml +0 -25
- data/test/internal/config/environment.rb +0 -5
- data/test/internal/config/environments/development.rb +0 -37
- data/test/internal/config/environments/production.rb +0 -83
- data/test/internal/config/environments/test.rb +0 -39
- data/test/internal/config/initializers/backtrace_silencers.rb +0 -7
- data/test/internal/config/initializers/cookies_serializer.rb +0 -3
- data/test/internal/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/internal/config/initializers/inflections.rb +0 -16
- data/test/internal/config/initializers/mime_types.rb +0 -4
- data/test/internal/config/initializers/session_store.rb +0 -3
- data/test/internal/config/initializers/wrap_parameters.rb +0 -14
- data/test/internal/config/locales/en.yml +0 -23
- data/test/internal/config/routes.rb +0 -3
- data/test/internal/config/secrets.yml +0 -22
- data/test/internal/config.ru +0 -4
- data/test/internal/db/.keep +0 -0
- data/test/internal/db/schema.rb +0 -7
- data/test/internal/db/seeds.rb +0 -1
- data/test/internal/lib/assets/.keep +0 -0
- data/test/internal/log/.gitignore +0 -1
- data/test/internal/log/.keep +0 -0
- data/test/internal/public/404.html +0 -67
- data/test/internal/public/422.html +0 -67
- data/test/internal/public/500.html +0 -66
- data/test/internal/public/favicon.ico +0 -0
- data/test/test_helper.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 44adb5a2de872bd288490c12dc5bc43863d8ab0805358a0d984c7fd442e2d0db
|
|
4
|
+
data.tar.gz: e2920b0dbf3c1b1ae06ee952db5ae73efced32699df8de0ec50ec95b18a1dc5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5174f5ca1a9c641154b31af30a4ccee7ed5904bc111131c886626f0820ef7e63d72f1b8c1deb81a8d3fffa371e627188f0dfd486abe721bd2596e63805b4673
|
|
7
|
+
data.tar.gz: 160eefc0e291f6706bafc9c57fd6a61f99986a0c11322e3ec682048e0d8447365fe3c27dcbdb9b242a78abd0a9ec4253e44666d3ca660f0c032f7230741277a7
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# Characterize
|
|
2
2
|
|
|
3
|
-
Make your models behave in special ways.
|
|
3
|
+
Make your models behave in special ways without wrapping them.
|
|
4
|
+
|
|
5
|
+
Characterize is built on top of [Casting](https://github.com/saturnflyer/casting) and makes it easy to get going in Rails.
|
|
6
|
+
|
|
7
|
+
[](https://codeclimate.com/github/saturnflyer/characterize)
|
|
8
|
+
[](http://badge.fury.io/rb/characterize)
|
|
4
9
|
|
|
5
10
|
## Usage
|
|
6
11
|
|
|
@@ -13,6 +18,12 @@ class UsersController < ApplicationController
|
|
|
13
18
|
end
|
|
14
19
|
# the above sets a helper_method of 'user' and loads UserCharacter
|
|
15
20
|
|
|
21
|
+
module UserCharacter
|
|
22
|
+
def special_behavior_available_in_the_view
|
|
23
|
+
# ...
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
16
27
|
class UsersController < ApplicationController
|
|
17
28
|
def show
|
|
18
29
|
characterize(user, display_module)
|
|
@@ -38,6 +49,83 @@ module StandardUser
|
|
|
38
49
|
end
|
|
39
50
|
```
|
|
40
51
|
|
|
52
|
+
Set special modules to be used for different actions:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
class UsersController < ApplicationController
|
|
56
|
+
characterize :user, show: [SpecialStuff, StandardStuff],
|
|
57
|
+
edit: [EditingCharacter],
|
|
58
|
+
default: [StandardStuff]
|
|
59
|
+
|
|
60
|
+
def show
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
By default Characterize will look for modules that match the name of your object. So `characterize :user` would apply a `UserCharacter` module (and will blow up if it can't find it.) Or you can override it with the above configuration.
|
|
66
|
+
|
|
67
|
+
You can also use it to characterize collections:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
class WidgetsController < ApplicationController
|
|
71
|
+
characterize_each :widgets, index: [SuperWidgetCharacter]
|
|
72
|
+
|
|
73
|
+
def index
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This will create a `widgets` helper method that will return a collection object where enumerable methods will cast the object as the provided modules.
|
|
79
|
+
|
|
80
|
+
By default these methods will assume a loading method for your records but you can override this:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
class UsersController < ApplicationController
|
|
84
|
+
characterize :user # creates a `load_user` method
|
|
85
|
+
characterize :user, load_with: :get_a_user
|
|
86
|
+
|
|
87
|
+
def get_a_user
|
|
88
|
+
UserRepository.get(params[:user_id])
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Altering the Settings
|
|
94
|
+
|
|
95
|
+
### Module names
|
|
96
|
+
|
|
97
|
+
Characterize will automatically look for modules using the "Character" suffix in it's name. But you can change this if you like.
|
|
98
|
+
|
|
99
|
+
Just create an initializer which will change the setting when your Rails application boots:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
Characterize.module_suffix = 'Details'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
With the above change, using `characterize :user` in your controller, it will attempt to load `UserDetails` instead of `UserCharacter`. This will apply for your *entire* application; if you only want to override the suffix in some places, just specify the module you want in your controller.
|
|
106
|
+
|
|
107
|
+
### Creating your own standard features
|
|
108
|
+
|
|
109
|
+
By default Characterize has some helpful features built in. You can use them like this:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
class UsersController < ApplicationController
|
|
113
|
+
characterize :user, show: [SpecialStuff].concat(Characterize.standard_features)
|
|
114
|
+
|
|
115
|
+
def show
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
That will load the built-in features from Characterize. But you can change what is considered "standard" in your application.
|
|
121
|
+
|
|
122
|
+
Set the `standard_features` option in your initializer to whatever you want:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
original_features = Characterize.standard_features
|
|
126
|
+
Characterize.standard_features = [MyAwesomeStuff, ExtraDoodads].concat(original_features)
|
|
127
|
+
```
|
|
128
|
+
|
|
41
129
|
## Installation
|
|
42
130
|
|
|
43
131
|
Add this line to your application's Gemfile:
|
|
@@ -48,6 +136,10 @@ And then execute:
|
|
|
48
136
|
|
|
49
137
|
$ bundle
|
|
50
138
|
|
|
139
|
+
And finally
|
|
140
|
+
|
|
141
|
+
$ rails g characterize:install
|
|
142
|
+
|
|
51
143
|
Or install it yourself as:
|
|
52
144
|
|
|
53
145
|
$ gem install characterize
|
data/Rakefile
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env rake
|
|
2
2
|
require "bundler/gem_tasks"
|
|
3
|
-
require
|
|
3
|
+
require "rake/testtask"
|
|
4
|
+
require "reissue/gem"
|
|
5
|
+
|
|
6
|
+
Reissue::Task.create :reissue do |task|
|
|
7
|
+
task.version_file = "lib/characterize/version.rb"
|
|
8
|
+
task.fragment = :git
|
|
9
|
+
end
|
|
4
10
|
|
|
5
11
|
Rake::TestTask.new do |t|
|
|
6
|
-
t.libs <<
|
|
7
|
-
t.test_files = FileList[
|
|
12
|
+
t.libs << "test"
|
|
13
|
+
t.test_files = FileList["test/*_test.rb"]
|
|
8
14
|
t.ruby_opts = ["-w"]
|
|
9
15
|
t.verbose = true
|
|
10
16
|
end
|
|
11
17
|
|
|
12
|
-
task :
|
|
13
|
-
system("cd test/internal && RAILS_ENV=test bundle exec rake db:reset")
|
|
14
|
-
end
|
|
15
|
-
Rake::Task[:test].enhance [:setup_db]
|
|
16
|
-
|
|
17
|
-
task :default => :test
|
|
18
|
+
task default: :test
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
module Characterize
|
|
6
|
+
class Collection
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def registry
|
|
11
|
+
@registry ||= {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Register a collection class to manage the given type
|
|
15
|
+
def register(klass, type)
|
|
16
|
+
registry[type] = klass
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Return an object handling the collection's type
|
|
20
|
+
#
|
|
21
|
+
# This will select the first matching class from which the collection's
|
|
22
|
+
# class inherits.
|
|
23
|
+
#
|
|
24
|
+
def for(collection, *behaviors)
|
|
25
|
+
klass = registry.find { |key, _value|
|
|
26
|
+
collection.class < key
|
|
27
|
+
}&.last || self
|
|
28
|
+
klass.new(collection, *behaviors)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def safe_command(*classes, receiver:)
|
|
32
|
+
standard = [:object_id, :__send__] +
|
|
33
|
+
Enumerator.instance_methods(false) +
|
|
34
|
+
Enumerable.instance_methods(false)
|
|
35
|
+
|
|
36
|
+
classes.each do |klass|
|
|
37
|
+
names = klass.instance_methods - standard - instance_methods(false)
|
|
38
|
+
command names => :collection
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
include Casting::Enum
|
|
44
|
+
def initialize(collection, *behaviors)
|
|
45
|
+
@behaviors = behaviors
|
|
46
|
+
reset_collection(collection)
|
|
47
|
+
end
|
|
48
|
+
attr :casted_enum, :collection, :behaviors
|
|
49
|
+
|
|
50
|
+
delegated_methods = (Enumerator.instance_methods(false) + Enumerable.instance_methods(false)).uniq - [:object_id, :inspect]
|
|
51
|
+
def_delegators :casted_enum, *delegated_methods
|
|
52
|
+
|
|
53
|
+
def inspect
|
|
54
|
+
%(#<#{self.class} #{object_id}>)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def reset_collection(collection)
|
|
60
|
+
@casted_enum = enum(collection, *behaviors)
|
|
61
|
+
@collection = collection
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
require "characterize/relation_collection"
|
|
@@ -1,67 +1,122 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "characterize/feature_set"
|
|
2
4
|
|
|
3
5
|
module Characterize
|
|
4
6
|
module Controller
|
|
5
7
|
def self.included(klass)
|
|
6
8
|
klass.extend(::Characterize::ControllerMacros)
|
|
9
|
+
klass.helper_method(:characterize)
|
|
7
10
|
end
|
|
8
|
-
|
|
11
|
+
|
|
9
12
|
private
|
|
10
13
|
|
|
14
|
+
# Apply character modules to the given object.
|
|
15
|
+
# This will use either the provided modules or if none are provided, the
|
|
16
|
+
# configured characters for the current controller action.
|
|
11
17
|
def characterize(obj, *mods)
|
|
12
|
-
obj.
|
|
18
|
+
object_name = obj.class.name.to_s.underscore
|
|
19
|
+
features = (!mods.empty?) ? mods : characters_for_action(object_name, action_name)
|
|
20
|
+
obj.__set_characterize_view__(view_context).cast_as(*features)
|
|
13
21
|
obj
|
|
14
22
|
end
|
|
15
23
|
|
|
16
24
|
def characters_for_action(object_name, action_name)
|
|
17
|
-
|
|
18
|
-
Array(self.send("#{object_name}_#{action_name}_characters"))
|
|
19
|
-
else
|
|
20
|
-
self.send("default_#{object_name}_characters")
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def self.view_features
|
|
25
|
-
[::Characterize::FeatureControls]
|
|
25
|
+
self.class.characterize_features.dig(object_name, action_name)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
module ControllerMacros
|
|
30
|
-
|
|
30
|
+
def self.attach_module(klass, name, &block)
|
|
31
|
+
mod = Module.new(&block)
|
|
32
|
+
klass.const_set(name, mod)
|
|
33
|
+
klass.include mod
|
|
34
|
+
|
|
35
|
+
mod
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def characterize_features
|
|
39
|
+
@characterize_features ||= FeatureSet.new
|
|
40
|
+
end
|
|
41
|
+
|
|
31
42
|
private
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
actions_hash
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
#{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
|
|
44
|
+
# Generate methods that will load and cast your object with the specified behaviors
|
|
45
|
+
def characterize(object_name, load_with: "load_#{object_name}", **actions_hash, &block)
|
|
46
|
+
characterize_features.add(object_name, **actions_hash)
|
|
47
|
+
|
|
48
|
+
mod = ControllerMacros.attach_module(
|
|
49
|
+
self,
|
|
50
|
+
"#{object_name.to_s.classify}ControllerMethods",
|
|
51
|
+
&block
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
unless method_defined?(load_with)
|
|
55
|
+
# def load_user
|
|
56
|
+
# User.find(params[:id])
|
|
57
|
+
# end
|
|
58
|
+
mod.module_eval <<~MOD, __FILE__, __LINE__ + 1
|
|
59
|
+
def #{load_with}
|
|
60
|
+
#{object_name.to_s.classify}.find(params[:id])
|
|
61
|
+
end
|
|
62
|
+
MOD
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
unless method_defined?(object_name)
|
|
66
|
+
# def user
|
|
67
|
+
# return @user if instance_variable_defined?(@user) && !@user.nil?
|
|
68
|
+
#
|
|
69
|
+
# @user = characterize(load_user, *characters_for_action(:user, action_name))
|
|
70
|
+
# end
|
|
71
|
+
mod.module_eval <<~MOD, __FILE__, __LINE__ + 1
|
|
72
|
+
def #{object_name}
|
|
73
|
+
return @#{object_name} if defined?(@#{object_name})
|
|
74
|
+
|
|
75
|
+
@#{object_name} = characterize(#{load_with}, *characters_for_action(__method__, action_name))
|
|
59
76
|
end
|
|
60
|
-
|
|
77
|
+
MOD
|
|
61
78
|
end
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
|
|
80
|
+
send(:helper_method, object_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def characterize_each(name, load_with: "load_#{name}", **actions_hash, &block)
|
|
84
|
+
characterize_features.add(name, **actions_hash)
|
|
85
|
+
|
|
86
|
+
constant_name = name.to_s.singularize.classify
|
|
87
|
+
mod = ControllerMacros.attach_module(
|
|
88
|
+
self,
|
|
89
|
+
"#{constant_name}CollectionControllerMethods",
|
|
90
|
+
&block
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
unless method_defined?(load_with)
|
|
94
|
+
# def load_users
|
|
95
|
+
# User.all
|
|
96
|
+
# end
|
|
97
|
+
mod.module_eval <<~MOD, __FILE__, __LINE__ + 1
|
|
98
|
+
def #{load_with}
|
|
99
|
+
#{constant_name}.all
|
|
100
|
+
end
|
|
101
|
+
MOD
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
unless method_defined?(name)
|
|
105
|
+
# def users
|
|
106
|
+
# return @users if @users.is_a?(Characterize::Collection)
|
|
107
|
+
#
|
|
108
|
+
# @users = Characterize::Collection.for(load_users, *characters_for_action(:users, action_name))
|
|
109
|
+
# end
|
|
110
|
+
mod.module_eval <<~MOD, __FILE__, __LINE__ + 1
|
|
111
|
+
def #{name}
|
|
112
|
+
return @#{name} if !@#{name}.nil? && @#{name}.is_a?(Characterize::Collection)
|
|
113
|
+
|
|
114
|
+
@#{name} = Characterize::Collection.for(#{load_with}, *characters_for_action(__method__, action_name))
|
|
115
|
+
end
|
|
116
|
+
MOD
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
send(:helper_method, name)
|
|
65
120
|
end
|
|
66
121
|
end
|
|
67
|
-
end
|
|
122
|
+
end
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
module Characterize
|
|
2
2
|
module FeatureControls
|
|
3
|
-
|
|
4
3
|
# Enumerate a collection with the given modules and block casting
|
|
5
4
|
# each object with the modules and uncasting the object afterward.
|
|
6
5
|
#
|
|
7
6
|
# Examples:
|
|
8
7
|
#
|
|
9
8
|
# def each_favorite(&block)
|
|
10
|
-
#
|
|
9
|
+
# each_with_features(favorites, FavoriteMod, &block)
|
|
11
10
|
# end
|
|
12
11
|
#
|
|
13
12
|
# <%- user.each_favorite do |favorite| %>
|
|
@@ -15,69 +14,92 @@ module Characterize
|
|
|
15
14
|
# <%- end -%>
|
|
16
15
|
#
|
|
17
16
|
def each_with_features(collection, *mods, &block)
|
|
18
|
-
collection.
|
|
19
|
-
obj.cast_as(*mods)
|
|
20
|
-
block.call(obj)
|
|
21
|
-
obj.uncast(mods.size)
|
|
22
|
-
end
|
|
17
|
+
Casting::Enum.enum(collection, *mods).each(&block)
|
|
23
18
|
end
|
|
24
|
-
|
|
19
|
+
|
|
25
20
|
# Conditionally render content for the object.
|
|
26
21
|
#
|
|
27
22
|
# Pass in a method name for content and either of:
|
|
28
23
|
# 1. options for Rails' content_tag
|
|
29
24
|
# 2. a block to render
|
|
30
25
|
#
|
|
26
|
+
# The value of the method call will be yielded to the block
|
|
27
|
+
#
|
|
31
28
|
# Examples:
|
|
32
29
|
#
|
|
33
30
|
# <%= user.with(:favorites, :p, class: 'favorites-details') %>
|
|
34
|
-
# <%- user.with(:favorites) do %>
|
|
31
|
+
# <%- user.with(:favorites) do |favorites| %>
|
|
35
32
|
# <p class="favorites-details">
|
|
36
|
-
# My Favorite Things: <%=
|
|
33
|
+
# My Favorite Things: <%= favorites.join(', ') %>
|
|
37
34
|
# </p>
|
|
38
35
|
# <%- end -%>
|
|
36
|
+
# <%= user.with(:favorites, :p, class: "whatever", without: "Oops! No favorites!")
|
|
39
37
|
#
|
|
40
|
-
def with(method_name,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
def with(method_name, tag_name = nil, **options, &block)
|
|
39
|
+
without_option = options.delete(:without)
|
|
40
|
+
method_value = public_send(method_name)
|
|
41
|
+
|
|
42
|
+
display_value = method_value.then do |method_value|
|
|
43
|
+
if with_conditions(method_name, method_value)
|
|
44
|
+
method_value
|
|
45
45
|
else
|
|
46
|
-
|
|
47
|
-
view.content_tag(tag_name, value, options)
|
|
46
|
+
without_option
|
|
48
47
|
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
capture_content = block || ->(_method_value = nil) do
|
|
51
|
+
__view__.concat(__view__.content_tag(tag_name, display_value, options))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if block
|
|
55
|
+
__view__.capture { capture_content.call(method_value) }
|
|
49
56
|
else
|
|
50
|
-
|
|
51
|
-
if without_option.respond_to?(:call)
|
|
52
|
-
without(method_name, &without_option)
|
|
53
|
-
else
|
|
54
|
-
view.concat(without_option)
|
|
55
|
-
end
|
|
57
|
+
__view__.capture { capture_content.call }
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
# Conditionally render content for the object when the attribute is NOT present.
|
|
60
62
|
#
|
|
61
63
|
# Pass in a method name and a block to render.
|
|
62
64
|
#
|
|
65
|
+
# The value of the method call will be yielded to the block
|
|
66
|
+
#
|
|
63
67
|
# Examples:
|
|
64
68
|
#
|
|
65
|
-
# <%- user.without(:favorites) do %>
|
|
69
|
+
# <%- user.without(:favorites) do |favorites| %>
|
|
66
70
|
# <p class="favorites-details none">
|
|
67
|
-
# There are no favorites here.
|
|
71
|
+
# There are no favorites here. You had <%= favorites %>
|
|
68
72
|
# </p>
|
|
69
73
|
# <%- end -%>
|
|
74
|
+
# <% user.without(:favorites, :p, value: 'No favorites!')
|
|
75
|
+
# <% user.without(:favorites, :p, value: "You should have favorites", with: "You DO have favorites!")
|
|
70
76
|
#
|
|
71
|
-
def without(method_name, &block)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
def without(method_name, tag_name = nil, value: nil, **options, &block)
|
|
78
|
+
with_option = options.delete(:with)
|
|
79
|
+
method_value = public_send(method_name)
|
|
80
|
+
|
|
81
|
+
display_value = method_value.then do |method_value|
|
|
82
|
+
if with_conditions(method_name, method_value)
|
|
83
|
+
with_option
|
|
84
|
+
else
|
|
85
|
+
value
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
capture_content = (block || ->(_method_value = nil) do
|
|
90
|
+
__view__.concat(__view__.content_tag(tag_name, display_value, options))
|
|
91
|
+
end)
|
|
92
|
+
|
|
93
|
+
if block
|
|
94
|
+
__view__.capture { capture_content.call(method_value) }
|
|
95
|
+
else
|
|
96
|
+
__view__.capture { capture_content.call }
|
|
75
97
|
end
|
|
76
98
|
end
|
|
77
|
-
|
|
99
|
+
|
|
78
100
|
# Used to override behavior of with for the case of special attributes
|
|
79
|
-
def with_conditions(
|
|
80
|
-
!computed_value.nil? && computed_value !=
|
|
101
|
+
def with_conditions(_method_name, computed_value)
|
|
102
|
+
!computed_value.nil? && computed_value != "" && computed_value != false
|
|
81
103
|
end
|
|
82
104
|
end
|
|
83
|
-
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "characterize/object_set"
|
|
4
|
+
|
|
5
|
+
module Characterize
|
|
6
|
+
class FeatureSet
|
|
7
|
+
def initialize
|
|
8
|
+
@object_rules = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add(object_name, **actions_hash)
|
|
12
|
+
@object_rules[object_name] = ObjectSet.new(object_name, **actions_hash)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def dig(*args)
|
|
16
|
+
@object_rules.dig(*args)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Characterize
|
|
4
|
+
class ObjectSet
|
|
5
|
+
def initialize(object_name, **hash)
|
|
6
|
+
@object_name = object_name
|
|
7
|
+
@hash = hash
|
|
8
|
+
end
|
|
9
|
+
attr :object_name
|
|
10
|
+
|
|
11
|
+
def dig(action_name, *_ignored)
|
|
12
|
+
if @hash.key?(action_name.to_sym)
|
|
13
|
+
Array(defaults + action_characters(action_name)).compact
|
|
14
|
+
else
|
|
15
|
+
defaults
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def object_class_name
|
|
20
|
+
@object_name.to_s.classify
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def object_character_name
|
|
24
|
+
"#{object_class_name}#{Characterize.module_suffix}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def object_character
|
|
28
|
+
return @object_character if defined?(@object_character)
|
|
29
|
+
@object_character = begin
|
|
30
|
+
Object.const_get(object_character_name)
|
|
31
|
+
rescue
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def defaults
|
|
37
|
+
Array(
|
|
38
|
+
Characterize.standard_features + @hash.fetch(:default, []) + [object_character]
|
|
39
|
+
).flatten.compact.uniq
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def action_object_character_name(action_name)
|
|
43
|
+
"#{action_name.to_s.classify}#{object_character_name}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def action_character(action_name)
|
|
47
|
+
Object.const_get(action_object_character_name(action_name))
|
|
48
|
+
rescue
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def action_characters(action_name)
|
|
53
|
+
Array(@hash.fetch(action_name.to_sym, [action_character(action_name)])).compact
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/characterize/railtie.rb
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
require "rails"
|
|
2
1
|
module Characterize
|
|
3
2
|
class Railtie < ::Rails::Railtie
|
|
4
|
-
|
|
5
3
|
config.after_initialize do |app|
|
|
6
|
-
app.config.paths.add
|
|
4
|
+
app.config.paths.add "app/characters", eager_load: true
|
|
7
5
|
end
|
|
8
6
|
|
|
9
7
|
if defined?(ActiveRecord)
|
|
10
|
-
initializer
|
|
8
|
+
initializer "characterize.active_record" do |app|
|
|
11
9
|
ActiveRecord::Base.send(:include, Characterize)
|
|
12
10
|
end
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
if defined?(Mongoid)
|
|
16
|
-
initializer
|
|
14
|
+
initializer "characterize.mongoid" do |app|
|
|
17
15
|
Mongoid::Document.send(:include, Characterize)
|
|
18
16
|
end
|
|
19
17
|
end
|
|
20
18
|
|
|
21
|
-
initializer
|
|
19
|
+
initializer "characterize.action_controller" do |app|
|
|
22
20
|
ActionController::Base.send(:include, Characterize::Controller)
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
|
-
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "direction"
|
|
4
|
+
|
|
5
|
+
module Characterize
|
|
6
|
+
class RelationCollection < Collection
|
|
7
|
+
Collection.register(self, ActiveRecord::Relation)
|
|
8
|
+
extend Direction
|
|
9
|
+
|
|
10
|
+
# Defined before safe_command/query so these names are excluded from the
|
|
11
|
+
# auto-generated delegators (see Collection.safe_command) rather than
|
|
12
|
+
# redefining them.
|
|
13
|
+
def not(...)
|
|
14
|
+
reset_collection collection.where.not(...)
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def limit(...)
|
|
19
|
+
reset_collection collection.limit(...)
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def offset(...)
|
|
24
|
+
reset_collection collection.offset(...)
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
safe_command ActiveRecord::QueryMethods, receiver: :collection
|
|
29
|
+
query ActiveRecord::Calculations.instance_methods => :collection
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/characterize/version.rb
CHANGED