mixit 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ -m markdown
2
+ --no-private
3
+ --hide-void-return
4
+ --no-cache
5
+ -
6
+ LICENSE.txt
7
+
8
+
@@ -0,0 +1,20 @@
1
+ Copyright (C) 2011 by Robert Gleeson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
data/README.md CHANGED
@@ -1,22 +1,24 @@
1
1
  | Project | Mixit
2
2
  |:----------------|:--------------------------------------------------
3
3
  | Homepage | https://github.com/robgleeson/Mixit
4
- | Documentation | http://rubydoc.info/gems/Mixit/frames
5
- | Author | Rob Gleeson
4
+ | Documentation | http://rubydoc.info/gems/mixit/frames
5
+ | Author | Rob Gleeson, Renato Riccieri Santos Zannon
6
6
 
7
7
 
8
8
  __DESCRIPTION__
9
9
 
10
- Mixit can be used to temporarily extend the calling scope of a block or object with instance methods from a module.
11
- It is written to help Domain Specific Language(DSL) writers provide a DSL with their own methods
12
- without losing the calling scope of the caller.
10
+ Mixit can be used to temporarily extend the calling scope of a block or
11
+ object with instance methods from a module.
12
+ It is written to help Domain Specific Language(DSL) writers provide a DSL
13
+ with their own methods without losing the calling scope of the caller.
13
14
 
14
15
  __WHY?__
15
16
 
16
17
  Some Ruby DSL approaches already exist(maybe one suits you):
17
18
 
18
19
  * `instance_eval`
19
- The calling scope is lost, and internal state is exposed to the user of the DSL.
20
+ The calling scope is lost, and internal state is exposed to the user of
21
+ the DSL.
20
22
 
21
23
  * `instance_eval` via "EmptyContext"
22
24
  The calling scope is lost, but the object is void of any state.
@@ -24,32 +26,31 @@ __WHY?__
24
26
  * Pass `self` onto the calling block.
25
27
  The cleanest approach but some of the beauty of the DSL can be lost.
26
28
 
27
- All these approaches(but the last) lose the calling scope, and that's why I created 'Mixit'.
28
- I wanted the user of the DSL to have access to the calling scope, but have access to my DSL as
29
- implicit receivers of 'self' as well.
29
+ All these approaches(but the last) lose the calling scope, and that's why I
30
+ created 'Mixit'.
31
+ I wanted the user of the DSL to have access to the calling scope, but have
32
+ access to my DSL as implicit receivers of 'self' as well.
30
33
 
31
34
  This approach is by no means 'perfect', or even 'good'.
32
35
  If you use it wisely, though, it can be a cool way to build nice DSLs.
33
36
 
34
37
 
35
-
36
38
  __EXAMPLES__
37
39
 
38
- Mix 'Foo' onto the 'self' referenced by _block_:
40
+ Temporarily mix 'Foo' onto the 'self' referenced by _block_:
39
41
 
40
- module Foo
41
- def bar
42
- end
42
+ module Foo
43
+ def bar() end
43
44
  end
44
45
 
45
- def DSL(&block)
46
- Mixit.mix(Foo, block)
47
- end
46
+ block = proc { }
48
47
 
49
- DSL do
50
- p respond_to?(:bar) # => true
48
+ Mixit.temporarily(Foo, block) do
49
+ p self.class # => Object
50
+ p respond_to?(:bar) # => true
51
51
  end
52
52
 
53
+ p self.class # => Object
53
54
  p respond_to?(:bar) # => false
54
55
 
55
56
  __INSTALL__
@@ -4,7 +4,24 @@ require "mixit/version"
4
4
  class Mixit
5
5
 
6
6
  class << self
7
-
7
+ #
8
+ # @overload mix(*modules, receiver, &block)
9
+ # Temporarily extends the __receiver__ with methods from __modules__.
10
+ #
11
+ # @param [Module] modules
12
+ # A variable number of modules to extend the receiver with.
13
+ #
14
+ # @param receiver
15
+ # (see Mixit#mix_onto)
16
+ #
17
+ # @param block
18
+ # (see Mixit#mix_onto)
19
+ #
20
+ # @yieldparam object
21
+ # (see Mixit#mix_onto)
22
+ #
23
+ # @return [void]
24
+ #
8
25
  def mix(*args, &block)
9
26
  case args.last
10
27
  when Proc
@@ -18,12 +35,39 @@ class Mixit
18
35
 
19
36
  new(modules).mix_onto(receiver, &block)
20
37
  end
38
+ alias_method :temporarily, :mix
21
39
  end
22
40
 
41
+
42
+ #
43
+ # @return [Array<Module>]
44
+ # An Array of Module objects.
45
+ #
46
+ attr_reader :modules
47
+
48
+ #
49
+ # @param [Array<Module>] modules
50
+ # An Array of Module objects.
51
+ #
23
52
  def initialize(modules)
24
- @modules = modules.map(&:clone)
53
+ @modules = modules
54
+ @clones = []
25
55
  end
26
56
 
57
+ #
58
+ # Temporarily extends __receiver__ with methods from {#modules modules}.
59
+ #
60
+ # @param [Object] receiver
61
+ # An object to temporarily extend.
62
+ #
63
+ # @param [Proc] block
64
+ # A block executed while the object is extended.
65
+ #
66
+ # @yieldparam [Object] object
67
+ # Yields a clone of the extended object (Optional).
68
+ #
69
+ # @return [void]
70
+ #
27
71
  def mix_onto(receiver, &block)
28
72
  if block.arity == 1
29
73
  block.call extend!(receiver, true)
@@ -32,15 +76,11 @@ class Mixit
32
76
  ivars = receiver.instance_variables
33
77
  extend!(receiver, false).instance_eval(&block)
34
78
  ensure
35
- # Remove instance variables added by @modules, or &block from 'receiver'.
36
- # We want to restore the calling scope to its previous state.
37
79
  (receiver.instance_variables - ivars).each do |ivar|
38
80
  receiver.send(:remove_instance_variable, ivar)
39
81
  end
40
82
 
41
- # Remove methods added by @modules from 'receiver'.
42
- # We want to restore the calling scope to its previous state.
43
- @modules.each do |mod|
83
+ @clones.each do |mod|
44
84
  mod.instance_methods(false).each do |meth|
45
85
  mod.send(:remove_method, meth)
46
86
  end
@@ -49,12 +89,25 @@ class Mixit
49
89
  end
50
90
  end
51
91
 
92
+ #
93
+ # Extends __receiver__ with the methods from {#modules modules}.
94
+ #
95
+ # @param receiver
96
+ # (see Mixit#mix_onto)
97
+ #
98
+ # @param [Boolean] to_be_cloned
99
+ # If true, a clone of the receiver is extended.
100
+ #
101
+ # @return [Object]
102
+ # Returns the extended object.
103
+ #
52
104
  def extend!(receiver, to_be_cloned=false)
53
105
  if to_be_cloned
54
106
  receiver = receiver.clone
55
107
  end
56
108
 
57
- @modules.inject(receiver) { |obj, mod| obj.extend(mod) }
109
+ @clones = @modules.map(&:clone)
110
+ @clones.inject(receiver) { |obj, mod| obj.extend(mod) }
58
111
  end
59
112
  private :extend!
60
113
 
@@ -1,3 +1,3 @@
1
1
  class Mixit
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -1,109 +1,105 @@
1
1
  context Mixit do
2
2
 
3
3
  context 'mix' do
4
- context 'When receiving a block.' do
5
- before do
6
- @module = Module.new do
7
- def callme
8
- :ok
9
- end
10
-
11
- def i
12
- @i = 'asdf'
13
- end
4
+ before do
5
+ @module = Module.new do
6
+ def callme
7
+ :ok
8
+ end
9
+
10
+ def set_ivar
11
+ @set_ivar = 'asdf'
12
+ end
13
+ end
14
+ end
15
+
16
+ context 'When receiving a block with no param.' do
17
+ it 'must provide access to mixed-in methods' do
18
+ block = proc { }
19
+
20
+ Mixit.mix(@module, block) do
21
+ callme.must_equal(:ok)
14
22
  end
15
23
  end
16
24
 
17
- context 'When extending the calling scope of a Proc.' do
18
- context 'Without cloning the receiver.' do
19
- it 'must provide access to mixed in module methoss' do
20
- block = proc { }
21
-
22
- Mixit.mix(@module, block) do
23
- callme.must_equal(:ok)
24
- end
25
- end
26
-
27
- it 'must provide access to surrounding locals.' do
28
- block = proc { }
29
- local = :ok
30
-
31
- Mixit.mix(@module, block) do
32
- local.must_equal(:ok)
33
- end
34
- end
35
-
36
- it 'must provide access to surrounding methods.' do
37
- def callme_() :ok end
38
- block = proc { }
39
-
40
- Mixit.mix(@module, block) do
41
- callme_.must_equal(:ok)
42
- end
43
- end
44
-
45
- it 'must remove instance variables added by the passed block.' do
46
- block = proc { }
47
-
48
- Mixit.mix(@module, block) do
49
- @ok = :no
50
- end
51
-
52
- instance_variable_defined?(:@ok).must_equal(false)
53
- end
54
-
55
- it 'must remove instance variables added by the mixed in modules.' do
56
- block = proc { }
57
-
58
- Mixit.mix(@module, block) do
59
- i
60
- instance_variable_defined?(:@i).must_equal(true)
61
- end
62
-
63
- instance_variable_defined?(:@i).must_equal(false)
64
- end
65
-
66
- it 'must not remove instance variables set before the scope is extended.' do
67
- block = proc {}
68
- @ok = :ok
69
-
70
- Mixit.mix(@module, block) do
71
- nil
72
- end
73
-
74
- instance_variable_defined?(:@ok).must_equal(true)
75
- end
76
-
77
- it 'must remove methods added by mixed in modules.' do
78
- block = proc {}
79
-
80
- Mixit.mix(@module, block) do
81
- nil
82
- end
83
-
84
- respond_to?(:callme).must_equal(false)
85
- end
25
+ it 'must provide access to surrounding locals.' do
26
+ block = proc { }
27
+ local = :ok
28
+
29
+ Mixit.mix(@module, block) do
30
+ local.must_equal(:ok)
31
+ end
32
+ end
33
+
34
+ it 'must provide access to surrounding methods.' do
35
+ def callme_() :ok end
36
+ block = proc { }
37
+
38
+ Mixit.mix(@module, block) do
39
+ callme_.must_equal(:ok)
40
+ end
41
+ end
42
+
43
+ it 'must remove instance variables added by the calling block.' do
44
+ block = proc { }
45
+
46
+ Mixit.mix(@module, block) do
47
+ @ok = :no
86
48
  end
49
+
50
+ instance_variable_defined?(:@ok).must_equal(false)
87
51
  end
88
52
 
89
- context 'With the receiver cloned.' do
90
- it 'must provide access to mixed in module methods.' do
91
- block = proc {}
53
+ it 'must remove instance variables added by mixed-in modules.' do
54
+ block = proc { }
92
55
 
93
- Mixit.mix(@module, block) do |receiver|
94
- receiver.callme.must_equal(:ok)
95
- end
56
+ Mixit.mix(@module, block) do
57
+ set_ivar
58
+ instance_variable_defined?(:@set_ivar).must_equal(true)
96
59
  end
97
60
 
98
- it 'must not extending the original receiver with mixed in module methods.' do
99
- block = proc {}
61
+ instance_variable_defined?(:@set_ivar).must_equal(false)
62
+ end
63
+
64
+ it 'must not remove pre-existing instance variables.' do
65
+ block = proc {}
66
+ @ok = :ok
67
+
68
+ Mixit.mix(@module, block) do
69
+ nil
70
+ end
71
+
72
+ instance_variable_defined?(:@ok).must_equal(true)
73
+ end
100
74
 
101
- Mixit.mix(@module, block) do |receiver|
102
- respond_to?(:callme).must_equal(false)
103
- end
75
+ it 'must remove methods added by mixed-in modules.' do
76
+ block = proc {}
77
+
78
+ Mixit.mix(@module, block) do
79
+ nil
104
80
  end
81
+
82
+ respond_to?(:callme).must_equal(false)
105
83
  end
106
84
  end
85
+
86
+ context 'When receiving a block with a extended object as a param.' do
87
+ it 'must provide access to mixed-in methods.' do
88
+ block = proc {}
89
+
90
+ Mixit.mix(@module, block) do |receiver|
91
+ receiver.callme.must_equal(:ok)
92
+ end
93
+ end
94
+
95
+ it 'must not extend the original receiver with mixed-in methods.' do
96
+ block = proc {}
97
+
98
+ Mixit.mix(@module, block) do |receiver|
99
+ respond_to?(:callme).must_equal(false)
100
+ end
101
+ end
102
+ end
107
103
  end
108
104
 
109
105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-19 00:00:00.000000000 Z
12
+ date: 2011-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70150457564540 !ruby/object:Gem::Requirement
16
+ requirement: &70339179578900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.9.2
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70150457564540
24
+ version_requirements: *70339179578900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &70150457564040 !ruby/object:Gem::Requirement
27
+ requirement: &70339179578400 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '2.5'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70150457564040
35
+ version_requirements: *70339179578400
36
36
  description: Temporarily extend the calling scope of a block with instance methods
37
37
  from a module.
38
38
  email:
@@ -43,7 +43,9 @@ extra_rdoc_files: []
43
43
  files:
44
44
  - .gitignore
45
45
  - .travis.yml
46
+ - .yardopts
46
47
  - Gemfile
48
+ - LICENSE.txt
47
49
  - README.md
48
50
  - Rakefile
49
51
  - lib/mixit.rb
@@ -66,7 +68,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
68
  version: '0'
67
69
  segments:
68
70
  - 0
69
- hash: -222401743341189092
71
+ hash: 2621427566551580532
70
72
  required_rubygems_version: !ruby/object:Gem::Requirement
71
73
  none: false
72
74
  requirements:
@@ -75,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
77
  version: '0'
76
78
  segments:
77
79
  - 0
78
- hash: -222401743341189092
80
+ hash: 2621427566551580532
79
81
  requirements: []
80
82
  rubyforge_project: mixit
81
83
  rubygems_version: 1.8.11