activesupport-decorators 0.9 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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