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.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +31 -6
  4. data/Rakefile +10 -9
  5. data/lib/characterize/collection.rb +65 -0
  6. data/lib/characterize/controller.rb +102 -41
  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 +24 -9
  15. data/lib/generators/characterize/install/install_generator.rb +16 -0
  16. data/lib/generators/characterize/templates/initializer.rb +9 -0
  17. metadata +26 -127
  18. data/.gitignore +0 -18
  19. data/.travis.yml +0 -16
  20. data/Gemfile +0 -14
  21. data/characterize.gemspec +0 -25
  22. data/test/characterize_test.rb +0 -14
  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/edit_user_character.rb +0 -5
  29. data/test/internal/app/characters/special_character.rb +0 -5
  30. data/test/internal/app/characters/user_character.rb +0 -2
  31. data/test/internal/app/controllers/application_controller.rb +0 -5
  32. data/test/internal/app/controllers/concerns/.keep +0 -0
  33. data/test/internal/app/controllers/users_controller.rb +0 -10
  34. data/test/internal/app/helpers/application_helper.rb +0 -2
  35. data/test/internal/app/mailers/.keep +0 -0
  36. data/test/internal/app/models/.keep +0 -0
  37. data/test/internal/app/models/concerns/.keep +0 -0
  38. data/test/internal/app/models/user.rb +0 -2
  39. data/test/internal/app/views/layouts/application.html.erb +0 -13
  40. data/test/internal/app/views/users/show.html.erb +0 -2
  41. data/test/internal/bin/bundle +0 -3
  42. data/test/internal/bin/rails +0 -4
  43. data/test/internal/bin/rake +0 -4
  44. data/test/internal/config/application.rb +0 -29
  45. data/test/internal/config/boot.rb +0 -5
  46. data/test/internal/config/database.yml +0 -21
  47. data/test/internal/config/environment.rb +0 -5
  48. data/test/internal/config/environments/development.rb +0 -37
  49. data/test/internal/config/environments/production.rb +0 -83
  50. data/test/internal/config/environments/test.rb +0 -39
  51. data/test/internal/config/initializers/backtrace_silencers.rb +0 -7
  52. data/test/internal/config/initializers/cookies_serializer.rb +0 -3
  53. data/test/internal/config/initializers/filter_parameter_logging.rb +0 -4
  54. data/test/internal/config/initializers/inflections.rb +0 -16
  55. data/test/internal/config/initializers/mime_types.rb +0 -4
  56. data/test/internal/config/initializers/session_store.rb +0 -3
  57. data/test/internal/config/initializers/wrap_parameters.rb +0 -14
  58. data/test/internal/config/locales/en.yml +0 -23
  59. data/test/internal/config/routes.rb +0 -3
  60. data/test/internal/config/secrets.yml +0 -22
  61. data/test/internal/config.ru +0 -4
  62. data/test/internal/db/.keep +0 -0
  63. data/test/internal/db/schema.rb +0 -7
  64. data/test/internal/db/seeds.rb +0 -1
  65. data/test/internal/lib/assets/.keep +0 -0
  66. data/test/internal/log/.gitignore +0 -1
  67. data/test/internal/log/.keep +0 -0
  68. data/test/internal/public/404.html +0 -67
  69. data/test/internal/public/422.html +0 -67
  70. data/test/internal/public/500.html +0 -66
  71. data/test/internal/public/favicon.ico +0 -0
  72. data/test/test_helper.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6dd6c5bddafaef5e7619904642a61bc18e4d3ceb
4
- data.tar.gz: b19c6b3417f70fed51cceaad19951ab356fd2c4c
2
+ SHA256:
3
+ metadata.gz: 44adb5a2de872bd288490c12dc5bc43863d8ab0805358a0d984c7fd442e2d0db
4
+ data.tar.gz: e2920b0dbf3c1b1ae06ee952db5ae73efced32699df8de0ec50ec95b18a1dc5d
5
5
  SHA512:
6
- metadata.gz: 604831f80be02bc1fa74f7d4db542ec6dd082d8b738364fd9cff991432c882df576aa7eebf396895198f83a8806d598ae8400bd4d39fd1da05beb6079cc1df7a
7
- data.tar.gz: b2d21c279d3c1752da601c02731f7c9dfa4f8ba3c6c03f3f3bd55324e11ea518f2cfaf8ded55d5c602f9d824c5312a85fdabbefffcacff00b53b971f18930c64
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
@@ -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
- [![Build Status](https://travis-ci.org/saturnflyer/characterize.png?branch=master)](https://travis-ci.org/saturnflyer/characterize)
8
7
  [![Code Climate](https://codeclimate.com/github/saturnflyer/characterize.png)](https://codeclimate.com/github/saturnflyer/characterize)
9
- [![Coverage Status](https://coveralls.io/repos/saturnflyer/characterize/badge.png)](https://coveralls.io/r/saturnflyer/characterize)
10
8
  [![Gem Version](https://badge.fury.io/rb/characterize.png)](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
- ## Atering the Settings
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 '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,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.__set_characterize_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)
11
21
  obj
12
22
  end
13
23
 
14
24
  def characters_for_action(object_name, action_name)
15
- if self.respond_to?("#{object_name}_#{action_name}_features") && action_methods.include?(action_name.to_s)
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
- def characterize(*options)
28
- object_name = options.shift
29
- actions_hash = options.last
30
-
31
- object_constant_name = object_name.to_s.gsub(/(?:^|_)([a-z])/){ $1.upcase }.gsub('/','::')
32
- default_features = actions_hash.delete(:default) || ["::#{object_constant_name}#{Characterize.module_suffix}"]
33
-
34
- mod = Module.new
35
- mod.module_eval %{
36
- def #{object_name}
37
- return @#{object_name} if defined?(@#{object_name})
38
- @#{object_name} = characterize(load_#{object_name}, *characters_for_action(:#{object_name}, action_name))
39
- end
40
-
41
- def load_#{object_name}
42
- #{object_constant_name}.find(params[:id])
43
- end
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
- self.const_set(object_constant_name + 'ControllerMethods', mod)
57
- include mod
58
- self.send(:helper_method, object_name)
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
- # 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.3"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,10 +1,19 @@
1
- require 'forwardable'
1
+ require "forwardable"
2
2
  module Characterize
3
3
  module ViewForwards
4
4
  extend Forwardable
5
-
6
- delegate [*ActionView::Helpers.constants.map{ |name|
7
- ActionView::Helpers.const_get(name)
8
- }.map(&:instance_methods).flatten] => :__view__
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