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.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +93 -1
  4. data/Rakefile +10 -9
  5. data/lib/characterize/collection.rb +65 -0
  6. data/lib/characterize/controller.rb +101 -46
  7. data/lib/characterize/feature_controls.rb +56 -34
  8. data/lib/characterize/feature_set.rb +19 -0
  9. data/lib/characterize/object_set.rb +56 -0
  10. data/lib/characterize/railtie.rb +5 -7
  11. data/lib/characterize/relation_collection.rb +31 -0
  12. data/lib/characterize/version.rb +1 -1
  13. data/lib/characterize/view_forwards.rb +15 -6
  14. data/lib/characterize.rb +44 -8
  15. data/lib/generators/characterize/install/install_generator.rb +16 -0
  16. data/lib/generators/characterize/templates/initializer.rb +9 -0
  17. metadata +26 -125
  18. data/.gitignore +0 -18
  19. data/.ruby-version +0 -1
  20. data/Gemfile +0 -10
  21. data/characterize.gemspec +0 -25
  22. data/test/characterize_test.rb +0 -8
  23. data/test/internal/README.rdoc +0 -28
  24. data/test/internal/Rakefile +0 -6
  25. data/test/internal/app/assets/images/.keep +0 -0
  26. data/test/internal/app/assets/javascripts/application.js +0 -13
  27. data/test/internal/app/assets/stylesheets/application.css +0 -15
  28. data/test/internal/app/characters/special_character.rb +0 -5
  29. data/test/internal/app/characters/user_character.rb +0 -2
  30. data/test/internal/app/controllers/application_controller.rb +0 -5
  31. data/test/internal/app/controllers/concerns/.keep +0 -0
  32. data/test/internal/app/controllers/users_controller.rb +0 -6
  33. data/test/internal/app/helpers/application_helper.rb +0 -2
  34. data/test/internal/app/mailers/.keep +0 -0
  35. data/test/internal/app/models/.keep +0 -0
  36. data/test/internal/app/models/concerns/.keep +0 -0
  37. data/test/internal/app/models/user.rb +0 -2
  38. data/test/internal/app/views/layouts/application.html.erb +0 -13
  39. data/test/internal/app/views/users/show.html.erb +0 -2
  40. data/test/internal/bin/bundle +0 -3
  41. data/test/internal/bin/rails +0 -4
  42. data/test/internal/bin/rake +0 -4
  43. data/test/internal/config/application.rb +0 -29
  44. data/test/internal/config/boot.rb +0 -5
  45. data/test/internal/config/database.yml +0 -25
  46. data/test/internal/config/environment.rb +0 -5
  47. data/test/internal/config/environments/development.rb +0 -37
  48. data/test/internal/config/environments/production.rb +0 -83
  49. data/test/internal/config/environments/test.rb +0 -39
  50. data/test/internal/config/initializers/backtrace_silencers.rb +0 -7
  51. data/test/internal/config/initializers/cookies_serializer.rb +0 -3
  52. data/test/internal/config/initializers/filter_parameter_logging.rb +0 -4
  53. data/test/internal/config/initializers/inflections.rb +0 -16
  54. data/test/internal/config/initializers/mime_types.rb +0 -4
  55. data/test/internal/config/initializers/session_store.rb +0 -3
  56. data/test/internal/config/initializers/wrap_parameters.rb +0 -14
  57. data/test/internal/config/locales/en.yml +0 -23
  58. data/test/internal/config/routes.rb +0 -3
  59. data/test/internal/config/secrets.yml +0 -22
  60. data/test/internal/config.ru +0 -4
  61. data/test/internal/db/.keep +0 -0
  62. data/test/internal/db/schema.rb +0 -7
  63. data/test/internal/db/seeds.rb +0 -1
  64. data/test/internal/lib/assets/.keep +0 -0
  65. data/test/internal/log/.gitignore +0 -1
  66. data/test/internal/log/.keep +0 -0
  67. data/test/internal/public/404.html +0 -67
  68. data/test/internal/public/422.html +0 -67
  69. data/test/internal/public/500.html +0 -66
  70. data/test/internal/public/favicon.ico +0 -0
  71. data/test/test_helper.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 00e40cca8ad8624b4a6ab85ab521ecdb08f2f689
4
- data.tar.gz: c791593bc4a01b224dfc37ee944417239b6e10a7
2
+ SHA256:
3
+ metadata.gz: 44adb5a2de872bd288490c12dc5bc43863d8ab0805358a0d984c7fd442e2d0db
4
+ data.tar.gz: e2920b0dbf3c1b1ae06ee952db5ae73efced32699df8de0ec50ec95b18a1dc5d
5
5
  SHA512:
6
- metadata.gz: e690b1251155f2cab4e14ae3a021efa95f68a99ad5ec2881032f7a3b774091b1eecdc45e1beb0ae6760d04a363781165ea6c683e72c68f117a6e824da2a5edf0
7
- data.tar.gz: f1613c4bd503315e41676a77daa47fe76a32c0a4fc460cb79d973000dc58df6d33a972f78a3c9e1b6ba555fe01ff01fdf9f210758c04b92f98f2255d371bc797
6
+ metadata.gz: c5174f5ca1a9c641154b31af30a4ccee7ed5904bc111131c886626f0820ef7e63d72f1b8c1deb81a8d3fffa371e627188f0dfd486abe721bd2596e63805b4673
7
+ data.tar.gz: 160eefc0e291f6706bafc9c57fd6a61f99986a0c11322e3ec682048e0d8447365fe3c27dcbdb9b242a78abd0a9ec4253e44666d3ca660f0c032f7230741277a7
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 'Jim Gay'
1
+ Copyright (c) 2014-2022 'Jim Gay'
2
2
 
3
3
  MIT License
4
4
 
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
+ [![Code Climate](https://codeclimate.com/github/saturnflyer/characterize.png)](https://codeclimate.com/github/saturnflyer/characterize)
8
+ [![Gem Version](https://badge.fury.io/rb/characterize.png)](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 'rake/testtask'
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 << 'test'
7
- t.test_files = FileList['test/*_test.rb']
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 :setup_db do |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
- require 'characterize/feature_controls'
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.__set_view__(view_context).cast_as(*mods)
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
- if self.respond_to?("#{object_name}_#{action_name}_characters") && action_methods.include?(action_name.to_s)
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
- def characterize(*options)
34
- object_name = options.shift
35
- actions_hash = options.last
36
-
37
- object_constant_name = object_name.to_s.gsub(/(?:^|_)([a-z])/){ $1.upcase }.gsub('/','::')
38
- default_characters = actions_hash.delete(:default) || ["::#{object_constant_name}Character"]
39
-
40
- mod = Module.new
41
- mod.module_eval %{
42
- def #{object_name}
43
- return @#{object_name} if defined?(@#{object_name})
44
- @#{object_name} = characterize(load_#{object_name}, *characters_for_action(:#{object_name}, action_name))
45
- end
46
-
47
- def load_#{object_name}
48
- #{object_constant_name}.find(params[:id])
49
- end
50
-
51
- def default_#{object_name}_characters
52
- [#{default_characters.map(&:to_s).join(', ')}]
53
- end
54
- }
55
- actions_hash.each_pair do |action_name, characters|
56
- mod.module_eval %{
57
- def #{object_name}_#{action_name}_characters
58
- [#{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])
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
- self.const_set(object_constant_name + 'ControllerMethods', mod)
63
- include mod
64
- self.send(:helper_method, object_name)
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
- # each_with_feature(favorites, FavoriteMod, &block)
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.lazy.each do |obj|
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: <%= user.favorites.join(', ') %>
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, *tag_name_or_options)
41
- value = self.public_send(method_name)
42
- if with_conditions(method_name, value)
43
- if block_given?
44
- yield
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
- tag_name, options = *tag_name_or_options
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
- without_option = tag_name_or_options.last.fetch(:without){ '' }
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
- value = self.public_send(method_name)
73
- if !with_conditions(method_name, value)
74
- yield
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(method_name, computed_value)
80
- !computed_value.nil? && computed_value != '' && computed_value != false
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
@@ -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 'app/characters', eager_load: true
4
+ app.config.paths.add "app/characters", eager_load: true
7
5
  end
8
6
 
9
7
  if defined?(ActiveRecord)
10
- initializer 'characterize.active_record' do |app|
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 'characterize.mongoid' do |app|
14
+ initializer "characterize.mongoid" do |app|
17
15
  Mongoid::Document.send(:include, Characterize)
18
16
  end
19
17
  end
20
18
 
21
- initializer 'characterize.action_controller' do |app|
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
@@ -1,3 +1,3 @@
1
1
  module Characterize
2
- VERSION = "0.0.2"
2
+ VERSION = "0.2.0"
3
3
  end