ruby-features 1.1.2 → 1.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.
- checksums.yaml +7 -0
- data/README.md +29 -19
- data/lib/ruby-features/concern/apply_to.rb +16 -5
- data/lib/ruby-features/version.rb +1 -1
- data/spec/define_spec.rb +32 -0
- metadata +14 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 27643cb1fa6b12baf10bf86fbc40226e2e70bc08
|
4
|
+
data.tar.gz: 2be53a6cc1404b1709b910fb8390663f4fc2d801
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c03d3cef6917da453e06c12184e31988366f42183ed170a6308049ce87dd8790dfafb3a41df9151a49672c7d1a161359634638f3873f11b60d0695cbdc89f6d0
|
7
|
+
data.tar.gz: 170853e803e73904e1755fc688e24032d45df28304a5f12427f4e9a3f259b3de9a6978afb6f67c36af5ee4da7fb12836a894a786abc078ccba58c22383ba8a44
|
data/README.md
CHANGED
@@ -5,10 +5,10 @@ Ruby Features
|
|
5
5
|
[](https://codeclimate.com/github/stokarenko/ruby-features)
|
6
6
|
[](https://codeclimate.com/github/stokarenko/ruby-features/coverage)
|
7
7
|
|
8
|
-
Ruby Features
|
8
|
+
Ruby Features allow the extending of Ruby classes and modules to become easy, safe and controlled.
|
9
9
|
|
10
10
|
## Why?
|
11
|
-
Lets ask, is good to write the code like this:
|
11
|
+
Lets ask, is that good to write the code like this:
|
12
12
|
```ruby
|
13
13
|
String.send :include, MyStringExtension
|
14
14
|
```
|
@@ -22,7 +22,7 @@ Object.class_eval do
|
|
22
22
|
end
|
23
23
|
```
|
24
24
|
|
25
|
-
The
|
25
|
+
The matter is in motivation to write such things. Lets skip the well-known reasons like
|
26
26
|
> Because I can! That is Ruby baby, lets make some anarchy!
|
27
27
|
|
28
28
|
but say:
|
@@ -37,12 +37,12 @@ library, infected by massive patches to core entities.
|
|
37
37
|
Ruby Features goal is to take that under control.
|
38
38
|
|
39
39
|
The main features are:
|
40
|
-
* No
|
40
|
+
* No dependencies;
|
41
41
|
* Built-in lazy load;
|
42
42
|
* Supports ActiveSupport lazy load as well;
|
43
43
|
* Stimulates the clear extending, but prevents monkey patching;
|
44
44
|
* Gives the control what core extensions to apply;
|
45
|
-
*
|
45
|
+
* Gives the understading who and how exactly affected to programming entities.
|
46
46
|
|
47
47
|
## requirements
|
48
48
|
* Ruby >= 1.9.3
|
@@ -68,7 +68,7 @@ to apply third-party features.
|
|
68
68
|
|
69
69
|
## Usage
|
70
70
|
### Feature definition
|
71
|
-
Feature file name should
|
71
|
+
Feature file name should end with `_feature.rb`.
|
72
72
|
|
73
73
|
Lets define the feature in `lib/features/something_useful_feature.rb`:
|
74
74
|
```ruby
|
@@ -80,6 +80,16 @@ RubyFeatures.define 'some_namespace/something_useful' do
|
|
80
80
|
attr_accessor :useful_variable
|
81
81
|
end
|
82
82
|
|
83
|
+
rewrite_instance_methods do
|
84
|
+
# rewrite instance methods
|
85
|
+
# call `super` to reach the rewritten method
|
86
|
+
def existing_instance_method
|
87
|
+
# some code before super
|
88
|
+
super
|
89
|
+
# some code after super
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
83
93
|
instance_methods do
|
84
94
|
# instance methods
|
85
95
|
def useful_instance_method
|
@@ -91,17 +101,17 @@ RubyFeatures.define 'some_namespace/something_useful' do
|
|
91
101
|
def useful_class_method
|
92
102
|
end
|
93
103
|
end
|
104
|
+
end
|
94
105
|
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
|
106
|
+
apply_to 'ActiveRecord::Relation' do
|
107
|
+
# feature can contain several apply_to definition
|
99
108
|
end
|
109
|
+
|
100
110
|
end
|
101
111
|
```
|
102
112
|
|
103
113
|
### Dependencies
|
104
|
-
The dependencies
|
114
|
+
The dependencies on other Ruby Features can be defined like:
|
105
115
|
```ruby
|
106
116
|
RubyFeatures.define 'main_feature' do
|
107
117
|
dependency 'dependent_feature1'
|
@@ -110,7 +120,7 @@ end
|
|
110
120
|
```
|
111
121
|
|
112
122
|
### Conditions
|
113
|
-
Sometimes
|
123
|
+
Sometimes it`s required to apply different things, depending on some criteria:
|
114
124
|
```ruby
|
115
125
|
RubyFeatures.define 'some_namespace/something_useful' do
|
116
126
|
apply_to 'ActiveRecord::Base' do
|
@@ -131,7 +141,7 @@ end
|
|
131
141
|
```
|
132
142
|
|
133
143
|
It's bad to do like that, because the mixin applied by Ruby Features became to be not static.
|
134
|
-
That
|
144
|
+
That causes unpredictable behavior.
|
135
145
|
|
136
146
|
Ruby Features provides the `conditions` mechanism to avoid such problem:
|
137
147
|
```ruby
|
@@ -156,7 +166,7 @@ RubyFeatures.define 'some_namespace/something_useful' do
|
|
156
166
|
end
|
157
167
|
```
|
158
168
|
|
159
|
-
All
|
169
|
+
All DSL methods support the conditions:
|
160
170
|
```ruby
|
161
171
|
apply_to 'ActiveRecord::Base', if: :first_criteria do; end
|
162
172
|
|
@@ -218,14 +228,14 @@ RubyFeatures.find_in_path(File.expand_path('../lib/features', __FILE__))
|
|
218
228
|
```
|
219
229
|
|
220
230
|
### Feature applying
|
221
|
-
Feature can be applied immediately after
|
231
|
+
Feature can be applied immediately after its definition:
|
222
232
|
```ruby
|
223
233
|
RubyFeatures.define 'some_namespace/something_useful' do
|
224
234
|
# definition
|
225
235
|
end.apply
|
226
236
|
```
|
227
237
|
|
228
|
-
Features can be applied
|
238
|
+
Features can be applied immediately after loading from path:
|
229
239
|
```ruby
|
230
240
|
RubyFeatures.find_in_path(File.expand_path('../lib/features', __FILE__)).apply_all
|
231
241
|
```
|
@@ -238,12 +248,12 @@ RubyFeatures.apply 'some_namespace/something_useful'
|
|
238
248
|
```
|
239
249
|
|
240
250
|
## Changes
|
251
|
+
### v1.2.0
|
252
|
+
* Added rewrite_instance_methods.
|
253
|
+
|
241
254
|
### v1.1.0
|
242
255
|
* Added conditions.
|
243
256
|
* Added dependencies.
|
244
257
|
|
245
|
-
## TODO
|
246
|
-
* ActionDispatch with ActiveSupport lazy_load
|
247
|
-
|
248
258
|
## License
|
249
259
|
MIT License. Copyright (c) 2015 Sergey Tokarenko
|
@@ -33,18 +33,29 @@ module RubyFeatures
|
|
33
33
|
_methods('Include', asserts, block)
|
34
34
|
end
|
35
35
|
|
36
|
+
def rewrite_instance_methods(asserts = {}, &block)
|
37
|
+
_methods('RewriteInstance', asserts, block)
|
38
|
+
end
|
39
|
+
|
36
40
|
def _apply_methods(target_class)
|
37
41
|
constants.each do |constant|
|
38
|
-
mixin_method, existing_methods_method = case(constant)
|
39
|
-
when /^Extend/ then [:extend, :methods]
|
40
|
-
when /^Include/ then [:include, :instance_methods]
|
42
|
+
mixin_method, existing_methods_method, existing_methods_check = case(constant)
|
43
|
+
when /^Extend/ then [:extend, :methods, :exclusion]
|
44
|
+
when /^Include/ then [:include, :instance_methods, :exclusion]
|
45
|
+
when /^RewriteInstance/ then [:prepend, :instance_methods, :inclusion]
|
41
46
|
else raise ArgumentError.new("Wrong mixin constant: #{constant}")
|
42
47
|
end
|
43
48
|
|
44
49
|
mixin = const_get(constant)
|
45
50
|
|
46
|
-
|
47
|
-
|
51
|
+
case(existing_methods_check)
|
52
|
+
when :exclusion
|
53
|
+
existing_methods = mixin.instance_methods & target_class.public_send(existing_methods_method)
|
54
|
+
raise NameError.new("Tried to #{mixin_method} already existing methods: #{existing_methods.inspect}") unless existing_methods.empty?
|
55
|
+
when :inclusion
|
56
|
+
not_existing_methods = mixin.instance_methods - target_class.public_send(existing_methods_method)
|
57
|
+
raise NameError.new("Tried to #{mixin_method} not existing methods: #{not_existing_methods.inspect}") unless not_existing_methods.empty?
|
58
|
+
end
|
48
59
|
|
49
60
|
target_class.send(mixin_method, mixin)
|
50
61
|
end
|
data/spec/define_spec.rb
CHANGED
@@ -31,6 +31,28 @@ describe RubyFeatures::Concern::Feature do
|
|
31
31
|
)
|
32
32
|
end
|
33
33
|
|
34
|
+
it 'should apply rewrite instance methods' do
|
35
|
+
test_class.class_eval do
|
36
|
+
def test_rewrite_instance_method
|
37
|
+
2
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
expect{
|
42
|
+
define_test_feature('rewrite_instance_methods_feature') do
|
43
|
+
rewrite_instance_methods do
|
44
|
+
def test_rewrite_instance_method
|
45
|
+
3 * super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end.apply
|
49
|
+
}.to change{test_class.new.test_rewrite_instance_method}.from(2).to(6)
|
50
|
+
|
51
|
+
expect(test_class.included_modules).to include(
|
52
|
+
RubyFeatures::Mixins::DefineTestModule::DefineTestClass::RewriteInstanceMethodsFeature::DefineTestModule::DefineTestClass::RewriteInstance
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
34
56
|
it 'should process applied block' do
|
35
57
|
expect{
|
36
58
|
define_test_feature('applied_block') do
|
@@ -75,4 +97,14 @@ describe RubyFeatures::Concern::Feature do
|
|
75
97
|
}.to raise_error(/Tried to include already existing methods: \[:existing_instance_method\]/)
|
76
98
|
end
|
77
99
|
|
100
|
+
it 'should raise error if target has no feature rewrite instance method' do
|
101
|
+
expect{
|
102
|
+
define_test_feature('not_existing_rewrite_instance_method') do
|
103
|
+
rewrite_instance_methods do
|
104
|
+
def not_existing_instance_method; end
|
105
|
+
end
|
106
|
+
end.apply
|
107
|
+
}.to raise_error(/Tried to prepend not existing methods: \[:not_existing_instance_method\]/)
|
108
|
+
end
|
109
|
+
|
78
110
|
end
|
metadata
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-features
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Sergey Tokarenko
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-08-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
description: Makes extending of Ruby classes and modules to be easy, safe and controlled.
|
@@ -33,23 +30,23 @@ executables: []
|
|
33
30
|
extensions: []
|
34
31
|
extra_rdoc_files: []
|
35
32
|
files:
|
33
|
+
- LICENSE
|
34
|
+
- README.md
|
36
35
|
- lib/generators/ruby_features/install_generator.rb
|
37
36
|
- lib/generators/ruby_features/templates/ruby-features.rb
|
37
|
+
- lib/ruby-features.rb
|
38
38
|
- lib/ruby-features/concern/apply_to.rb
|
39
39
|
- lib/ruby-features/concern/feature.rb
|
40
40
|
- lib/ruby-features/conditions.rb
|
41
41
|
- lib/ruby-features/container.rb
|
42
42
|
- lib/ruby-features/lazy.rb
|
43
43
|
- lib/ruby-features/mixins.rb
|
44
|
+
- lib/ruby-features/utils.rb
|
44
45
|
- lib/ruby-features/utils/const_accessor_19.rb
|
45
46
|
- lib/ruby-features/utils/const_accessor_20.rb
|
46
47
|
- lib/ruby-features/utils/inflector.rb
|
47
48
|
- lib/ruby-features/utils/inflector_active_support.rb
|
48
|
-
- lib/ruby-features/utils.rb
|
49
49
|
- lib/ruby-features/version.rb
|
50
|
-
- lib/ruby-features.rb
|
51
|
-
- LICENSE
|
52
|
-
- README.md
|
53
50
|
- spec/conditions_spec.rb
|
54
51
|
- spec/define_spec.rb
|
55
52
|
- spec/find_and_apply_spec.rb
|
@@ -62,27 +59,26 @@ files:
|
|
62
59
|
homepage: https://github.com/stokarenko/ruby-features
|
63
60
|
licenses:
|
64
61
|
- MIT
|
62
|
+
metadata: {}
|
65
63
|
post_install_message:
|
66
64
|
rdoc_options: []
|
67
65
|
require_paths:
|
68
66
|
- lib
|
69
67
|
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
-
none: false
|
71
68
|
requirements:
|
72
|
-
- -
|
69
|
+
- - ">="
|
73
70
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
71
|
+
version: 2.0.0
|
75
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
73
|
requirements:
|
78
|
-
- -
|
74
|
+
- - ">="
|
79
75
|
- !ruby/object:Gem::Version
|
80
76
|
version: '0'
|
81
77
|
requirements: []
|
82
78
|
rubyforge_project:
|
83
|
-
rubygems_version:
|
79
|
+
rubygems_version: 2.5.1
|
84
80
|
signing_key:
|
85
|
-
specification_version:
|
81
|
+
specification_version: 4
|
86
82
|
summary: Makes extending of Ruby classes and modules to be easy, safe and controlled.
|
87
83
|
test_files:
|
88
84
|
- spec/conditions_spec.rb
|