activesupport-decorators 0.9 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec2236b08c2f672564e38201de862f16d36077b3
4
- data.tar.gz: a0d82c89cd824d7699eafc8114d6ad5aa28b9483
3
+ metadata.gz: 7ac0e53aa4f0f2a5552ebdffb9bc6f8862bfb583
4
+ data.tar.gz: 0bc4b6985d4c867c732345478627e3ed2c69be1f
5
5
  SHA512:
6
- metadata.gz: 0cf349af37ab49b04a3963a0e439dadbe008494ad8aad5f2b1d344959594153811d8c52d304e69cf2118675a73383d591517d342a86a7a939c49f93553090299
7
- data.tar.gz: 19691a0734337d8c0ff8cebe4b027be8b2154e7c55dc6d36c11d285393e87fc3ca1d0aac48ceb950b5b0299a6635133f0a7fb42d829ba8fe8fd9a280cf0f82ae
6
+ metadata.gz: a7ea6a25f3474820c952786c12d9c04d6062ee8bc398b2b003170432561ef479bc82d32a3367f86640349c5d204da5ca4832078e4eeccad10163fe1129b3bb46
7
+ data.tar.gz: d68066a4e76725ffd03bfd4efa174f7fed47ebc686f006c9e458b551ef311a6d72bee37e8f039b492b942f87fdd612612d2df3154a4b8a8559bcd49d9a93c6a3
data/README.md CHANGED
@@ -1,54 +1,111 @@
1
- ActiveSupportDecorators
2
- =======================
1
+ ActiveSupport Decorators
2
+ ========================
3
3
 
4
- The decorator pattern is particularly useful when extending constants in rails engines or vica versa. To implement
4
+ The decorator pattern is particularly useful when extending constants in rails engines or vice versa. To implement
5
5
  the decorator pattern, you need to load the decorator after the original file has been loaded. When you reference a
6
6
  class in a Rails application, ActiveSupport will only load the first file it finds that matches the class name. This
7
7
  means that you will need to manually load the additional (decorator) file. Usually you don't want to want to introduce
8
8
  hard dependencies such as require statements. You also don't want to preload a bunch of classes in a Rails initializer.
9
- This is a tiny gem that provides you with a simple way to specify load dependencies.
9
+ This is a tiny gem that provides you with a simple way to specify load file dependencies.
10
10
 
11
- Example
12
- =======
11
+ ## Installation
13
12
 
14
- Lets say your main rails application defines a model called Pet (in app/models/pet.rb):
13
+ Add it to your Gemfile and run bundle install:
14
+
15
+ ```Ruby
16
+ gem 'activesupport-decorators', '~> 1.0'
17
+ ```
18
+
19
+ ## Example 1 - Engine extends application class.
20
+
21
+ Your main rails application defines a model called Pet (in app/models/pet.rb):
15
22
 
16
23
  ```Ruby
17
24
  class Pet < ActiveRecord::Base
18
25
  end
19
26
  ```
20
27
 
21
- Your rails engine adds the concept of pet owners to the application. You can extend the Pet model in the engine with
22
- the following model decorator (in my_engine/app/models/pet.rb).
28
+ Your rails engine adds the concept of pet owners to the application. You extend the Pet model in the engine with
29
+ the following model decorator (in my_engine/app/models/pet_decorator.rb).
23
30
 
24
31
  ```Ruby
25
- class Pet
32
+ Pet.class_eval do
26
33
  belongs_to :owner
27
34
  end
28
35
  ```
29
36
 
30
- Now tell ActiveSupportDecorators to load any matching file in my_engine/app/models when a file is loaded from
31
- app/models. A convenient place to do this is in a Rails initializer in the engine:
37
+ Now tell ActiveSupportDecorators to load any matching decorator file in my_engine/app when a file is loaded from
38
+ app/. A convenient place to do this is in a Rails initializer in the engine:
32
39
 
33
40
  ```Ruby
34
41
  module MyEngine
35
42
  module Rails
36
43
  class Engine < ::Rails::Engine
37
- initializer :decorator_dependencies do |app|
38
- ActiveSupportDecorators.add_dependency("#{app.root}/app/models", "#{config.root}/app/models")
44
+ initializer :set_decorator_dependencies do |app|
45
+ ActiveSupportDecorators.add("#{app.root}/app", "#{config.root}/app")
39
46
  end
40
47
  end
41
48
  end
42
49
  end
43
50
  ```
44
51
 
45
- Note that you could specify the path as "/app" to allow decorating controllers, models, helpers, etc.
52
+ ## Example 2 - Application extends engine class.
53
+
54
+ Similar to the example above except the initializer is placed in the main application instead of the engine. Create a
55
+ file called config/initializers/set_decorator_dependencies.rb (or any other name) with content:
56
+
57
+ ```Ruby
58
+ ActiveSupportDecorators.add("#{MyEngine::Rails::Engine.root}/app", "#{Rails.root}/app")
59
+ ```
46
60
 
47
- Debugging
48
- =========
61
+ ## Example 3 - Engine extends another engine class.
62
+
63
+ ```Ruby
64
+ module MyEngine
65
+ module Rails
66
+ class Engine < ::Rails::Engine
67
+ initializer :set_decorator_dependencies do |app|
68
+ ActiveSupportDecorators.add("#{AnotherEngine::Rails::Engine.root}/app", "#{Rails.root}/app")
69
+ end
70
+ end
71
+ end
72
+ end
73
+ ```
74
+
75
+ ## Debugging
49
76
 
50
77
  Need to know which decorator files are loaded? Enable debug output:
51
78
 
52
79
  ```Ruby
53
80
  ActiveSupportDecorators.debug = true
54
- ```
81
+ ```
82
+
83
+ ## Decorator file pattern
84
+
85
+ By default decorator files are matched with '_decorator' appended to the file name. You can remove this suffix
86
+ completely or use your own one. Note the method signature of add:
87
+
88
+ ```Ruby
89
+ ActiveSupportDecorators.add(path, decorator_path, file_pattern = '_decorator')
90
+ ```
91
+
92
+ ## Decorating decorators
93
+
94
+ Nested decorators are supported. Just set them to decorate a path where the dependant decorators are placed.
95
+
96
+ ## Comparison to other gems
97
+
98
+ This is yet another decorator gem because it:
99
+ * allows you to specify where and how you name decorators.
100
+ * allows you to limit the paths you decorate.
101
+ * other gems tend to eager load as seen [here]
102
+ (https://github.com/atd/rails_engine_decorators/blob/master/lib/rails_engine_decorators/engine/configuration.rb)
103
+ and [here](https://github.com/parndt/decorators/blob/master/lib/decorators/railtie.rb).
104
+ * other gems assume you use 'MyClass.class_eval' to define decorators since it is how you trigger activesupport to load
105
+ the original file. This gem allows you to use the normal 'class MyClass' which means you can define constants in
106
+ decorators.
107
+
108
+ However if you do not want to specify which path's you allow to be decorated, you should use another gem. Instead of
109
+ single file look ups it will need to search your decorator directories for a matching file, which is not feasible
110
+ especially in a context where any ruby file may be decorated. The best solution for such a scenario would be to
111
+ eager load the decorators like other gems do.
@@ -1,16 +1,18 @@
1
1
  require 'active_support_decorators/graph'
2
2
 
3
3
  module ActiveSupportDecorators
4
+ Dependency = Struct.new(:path, :decorator_path, :file_pattern)
5
+
6
+ def self.clear
7
+ dependencies.clear
8
+ end
9
+
4
10
  def self.dependencies
5
- @dependencies ||= {}
11
+ @dependencies ||= []
6
12
  end
7
13
 
8
- def self.add_dependency(path, decorator_path)
9
- if dependencies.include?(path)
10
- dependencies[path] << decorator_path
11
- else
12
- dependencies[path] = [decorator_path]
13
- end
14
+ def self.add(path, decorator_path, file_pattern = '_decorator')
15
+ dependencies << Dependency.new(path, decorator_path, file_pattern)
14
16
  end
15
17
 
16
18
  def self.debug
@@ -21,37 +23,37 @@ module ActiveSupportDecorators
21
23
  @debug = debugging_enabled
22
24
  end
23
25
 
26
+ private
24
27
  def self.load_path_order(file_name)
25
- graph = Graph.new
26
- graph.add(file_name)
28
+ # Do not process with .rb extension if provided.
29
+ sanitized_file_name = file_name.sub(/\.rb$/,'')
27
30
 
28
- # If an attempt is made to load the original file, ensure the decorators are loaded afterwards.
29
- dependencies.each do |path, decorator_paths|
30
- if file_name.starts_with?(path)
31
- relative_name = file_name.gsub(path, '')
31
+ graph = Graph.new
32
+ graph.add(sanitized_file_name)
32
33
 
33
- decorator_paths.each do |decorator_path|
34
- decorator_file = "#{decorator_path}#{relative_name}"
34
+ dependencies.each do |dep|
35
+ # If an attempt is made to load the original file, ensure the decorators are loaded afterwards.
36
+ if sanitized_file_name.starts_with?(dep.path)
37
+ relative_name = sanitized_file_name.sub(dep.path, '')
38
+ decorator_file = "#{dep.decorator_path}#{relative_name}#{dep.file_pattern}"
35
39
 
36
- if File.file?(decorator_file) || File.file?(decorator_file + '.rb')
37
- graph.add_dependency(file_name, decorator_file)
38
- end
40
+ if File.file?(decorator_file + '.rb')
41
+ graph.add_with_edge(sanitized_file_name, decorator_file)
39
42
  end
40
43
  end
41
44
 
42
- # If an attempt is made to load a decorator file, ensure the original file is loaded first.
43
- decorator_paths.each do |decorator_path|
44
- if file_name.starts_with?(decorator_path)
45
- relative_name = file_name.gsub(decorator_path, '')
46
- decorated_file = "#{path}#{relative_name}"
45
+ # If an attempt is made to load a decorator file, ensure the original/decorated file is loaded first.
46
+ # This is only supported when a decorator was not added with add_global.
47
+ if dep.path && sanitized_file_name.starts_with?(dep.decorator_path)
48
+ relative_name = sanitized_file_name.sub(dep.decorator_path, '')
49
+ decorated_file = "#{dep.path}#{relative_name}".sub(/#{dep.file_pattern}$/, '')
47
50
 
48
- if File.file?(decorated_file) || File.file?(decorated_file + '.rb')
49
- graph.add_dependency(decorated_file, file_name)
50
- end
51
+ if File.file?(decorated_file + '.rb')
52
+ graph.add_with_edge(decorated_file, sanitized_file_name)
51
53
  end
52
54
  end
53
55
  end
54
56
 
55
- graph.resolve_object_order
57
+ graph.list_by_order
56
58
  end
57
- end
59
+ end
@@ -14,4 +14,4 @@ module ActiveSupport::Dependencies
14
14
  require_or_load_without_multiple(path, const_path)
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -9,7 +9,7 @@ class Graph
9
9
  @nodes = []
10
10
  end
11
11
 
12
- def resolve_object_order
12
+ def list_by_order
13
13
  result = []
14
14
 
15
15
  until @nodes.empty?
@@ -29,14 +29,15 @@ class Graph
29
29
  find_or_add_node(object)
30
30
  end
31
31
 
32
- def add_dependency(from_object, to_object)
33
- raise 'Objects are identical' if from_object == to_object
32
+ def add_with_edge(from_object, to_object)
33
+ fail 'Can not add edge from object to itself' if from_object == to_object
34
34
  from_node = find_or_add_node(from_object)
35
35
  to_node = find_or_add_node(to_object)
36
36
  to_node.depends_on << from_node
37
- raise 'EMPTY' if from_node.nil?
37
+ fail 'EMPTY' if from_node.nil?
38
38
  end
39
39
 
40
+ private
40
41
  def find_or_add_node(object)
41
42
  node = @nodes.find { |n| n.object == object }
42
43
  unless node
@@ -1,3 +1,3 @@
1
1
  module ActiveSupportDecorators
2
- VERSION = '0.9'
2
+ VERSION = '1.0.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport-decorators
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.9'
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Pretorius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-28 00:00:00.000000000 Z
11
+ date: 2014-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.0'
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
27
41
  description: Useful when extending functionality with Rails engines.
28
42
  email:
29
43
  - pierre@labs.epiuse.com