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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ac0e53aa4f0f2a5552ebdffb9bc6f8862bfb583
|
4
|
+
data.tar.gz: 0bc4b6985d4c867c732345478627e3ed2c69be1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7ea6a25f3474820c952786c12d9c04d6062ee8bc398b2b003170432561ef479bc82d32a3367f86640349c5d204da5ca4832078e4eeccad10163fe1129b3bb46
|
7
|
+
data.tar.gz: d68066a4e76725ffd03bfd4efa174f7fed47ebc686f006c9e458b551ef311a6d72bee37e8f039b492b942f87fdd612612d2df3154a4b8a8559bcd49d9a93c6a3
|
data/README.md
CHANGED
@@ -1,54 +1,111 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
ActiveSupport Decorators
|
2
|
+
========================
|
3
3
|
|
4
|
-
The decorator pattern is particularly useful when extending constants in rails engines or
|
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
|
-
|
12
|
-
=======
|
11
|
+
## Installation
|
13
12
|
|
14
|
-
|
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
|
22
|
-
the following model decorator (in my_engine/app/models/
|
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
|
-
|
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
|
31
|
-
app
|
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 :
|
38
|
-
ActiveSupportDecorators.
|
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
|
-
|
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
|
-
|
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.
|
9
|
-
|
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
|
-
|
26
|
-
|
28
|
+
# Do not process with .rb extension if provided.
|
29
|
+
sanitized_file_name = file_name.sub(/\.rb$/,'')
|
27
30
|
|
28
|
-
|
29
|
-
|
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
|
-
|
34
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
49
|
-
|
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.
|
57
|
+
graph.list_by_order
|
56
58
|
end
|
57
|
-
end
|
59
|
+
end
|
@@ -9,7 +9,7 @@ class Graph
|
|
9
9
|
@nodes = []
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
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
|
33
|
-
|
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
|
-
|
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
|
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:
|
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-
|
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: '
|
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: '
|
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
|