characterize 0.0.3 → 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 +31 -6
- data/Rakefile +10 -9
- data/lib/characterize/collection.rb +65 -0
- data/lib/characterize/controller.rb +102 -41
- 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 +24 -9
- data/lib/generators/characterize/install/install_generator.rb +16 -0
- data/lib/generators/characterize/templates/initializer.rb +9 -0
- metadata +26 -127
- data/.gitignore +0 -18
- data/.travis.yml +0 -16
- data/Gemfile +0 -14
- data/characterize.gemspec +0 -25
- data/test/characterize_test.rb +0 -14
- 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/edit_user_character.rb +0 -5
- 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 -10
- 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 -21
- 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 -25
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
|
@@ -4,14 +4,9 @@ Make your models behave in special ways without wrapping them.
|
|
|
4
4
|
|
|
5
5
|
Characterize is built on top of [Casting](https://github.com/saturnflyer/casting) and makes it easy to get going in Rails.
|
|
6
6
|
|
|
7
|
-
[](https://travis-ci.org/saturnflyer/characterize)
|
|
8
7
|
[](https://codeclimate.com/github/saturnflyer/characterize)
|
|
9
|
-
[](https://coveralls.io/r/saturnflyer/characterize)
|
|
10
8
|
[](http://badge.fury.io/rb/characterize)
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
10
|
## Usage
|
|
16
11
|
|
|
17
12
|
```ruby
|
|
@@ -69,7 +64,33 @@ end
|
|
|
69
64
|
|
|
70
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.
|
|
71
66
|
|
|
72
|
-
|
|
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
|
|
73
94
|
|
|
74
95
|
### Module names
|
|
75
96
|
|
|
@@ -115,6 +136,10 @@ And then execute:
|
|
|
115
136
|
|
|
116
137
|
$ bundle
|
|
117
138
|
|
|
139
|
+
And finally
|
|
140
|
+
|
|
141
|
+
$ rails g characterize:install
|
|
142
|
+
|
|
118
143
|
Or install it yourself as:
|
|
119
144
|
|
|
120
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,61 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "characterize/feature_set"
|
|
4
|
+
|
|
1
5
|
module Characterize
|
|
2
6
|
module Controller
|
|
3
7
|
def self.included(klass)
|
|
4
8
|
klass.extend(::Characterize::ControllerMacros)
|
|
9
|
+
klass.helper_method(:characterize)
|
|
5
10
|
end
|
|
6
|
-
|
|
11
|
+
|
|
7
12
|
private
|
|
8
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.
|
|
9
17
|
def characterize(obj, *mods)
|
|
10
|
-
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)
|
|
11
21
|
obj
|
|
12
22
|
end
|
|
13
23
|
|
|
14
24
|
def characters_for_action(object_name, action_name)
|
|
15
|
-
|
|
16
|
-
Array(self.send("#{object_name}_#{action_name}_features"))
|
|
17
|
-
else
|
|
18
|
-
self.send("default_#{object_name}_features")
|
|
19
|
-
end
|
|
25
|
+
self.class.characterize_features.dig(object_name, action_name)
|
|
20
26
|
end
|
|
21
27
|
end
|
|
22
|
-
|
|
28
|
+
|
|
23
29
|
module ControllerMacros
|
|
24
|
-
|
|
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
|
+
|
|
25
42
|
private
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
actions_hash
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def default_#{object_name}_features
|
|
46
|
-
[#{default_features.map(&:to_s).join(', ')}]
|
|
47
|
-
end
|
|
48
|
-
}
|
|
49
|
-
actions_hash.each_pair do |action_name, characters|
|
|
50
|
-
mod.module_eval %{
|
|
51
|
-
def #{object_name}_#{action_name}_features
|
|
52
|
-
[#{characters.map(&:to_s).join(', ')}]
|
|
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])
|
|
53
61
|
end
|
|
54
|
-
|
|
62
|
+
MOD
|
|
55
63
|
end
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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))
|
|
76
|
+
end
|
|
77
|
+
MOD
|
|
78
|
+
end
|
|
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)
|
|
59
120
|
end
|
|
60
121
|
end
|
|
61
|
-
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
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "forwardable"
|
|
2
2
|
module Characterize
|
|
3
3
|
module ViewForwards
|
|
4
4
|
extend Forwardable
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
|
|
6
|
+
# Find all view helper modules
|
|
7
|
+
action_view_helpers = ActionView::Helpers.constants.map { |name|
|
|
8
|
+
ActionView::Helpers.const_get(name)
|
|
9
|
+
}.select { |const|
|
|
10
|
+
const.is_a?(Module)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# Forward view helper module methods to the view object
|
|
14
|
+
delegate [*action_view_helpers.map(&:instance_methods).flatten.uniq] => :__view__
|
|
15
|
+
|
|
16
|
+
# Forward URL helper module methods to the view object
|
|
17
|
+
delegate [*Rails.application.routes.url_helpers.instance_methods] => :__view__
|
|
9
18
|
end
|
|
10
|
-
end
|
|
19
|
+
end
|