ruby-features 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Climate](https://codeclimate.com/github/stokarenko/ruby-features/badges/gpa.svg)](https://codeclimate.com/github/stokarenko/ruby-features)
|
6
6
|
[![Coverage](https://codeclimate.com/github/stokarenko/ruby-features/badges/coverage.svg)](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
|