implicitly 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ = Synopsis
2
+
3
+ Implicits in Ruby, based on Scala. Works like:
4
+
5
+ implicitly.from(BaseClass).to(WrapperClass).via do |base_object|
6
+ WrapperClass.new(base_object)
7
+ end
8
+
9
+ = Example
10
+
11
+ For example, to extend Fixnum with #seconds, #minutes, and #hours:
12
+
13
+ class FixnumWithTime
14
+ def initialize(n)
15
+ @n = n
16
+ end
17
+
18
+ def minutes
19
+ seconds * 60
20
+ end
21
+
22
+ def hours
23
+ minutes * 60
24
+ end
25
+
26
+ def seconds
27
+ @n
28
+ end
29
+ end
30
+
31
+ class Person
32
+ implicitly.from(Fixnum).to(FixnumWithTime).via do |fixnum|
33
+ FixnumWithTime.new(fixnum)
34
+ end
35
+
36
+ def age_in_seconds
37
+ 37.minutes
38
+ end
39
+ end
40
+
41
+ = Why
42
+
43
+ By using a wrapping class the extension can be tested independently of the base
44
+ class.
45
+
46
+ = Author
47
+
48
+ Mike Burns
49
+ mburns@thoughtbot.com
50
+ http://mike-burns.com/
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ t.test_files = FileList['test/test*.rb']
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
@@ -0,0 +1,54 @@
1
+ class Module
2
+ # Set up the implicit handling. Use the #from #to and #via methods to specify
3
+ # the full transformation. For example:
4
+ #
5
+ # implicit.from(Fixnum).to(FixnumWithTime).via {|number| FixnumWithTime.new(number) }
6
+ #
7
+ # Nothing takes effect until all three (#from #to and #via) are set.
8
+ #
9
+ # The above implicit will transform a Fixnum instance into a FixnumWithTime
10
+ # wrapper, but only when you call a public instance method which is defined
11
+ # in FixnumWithTime.
12
+ def implicitly
13
+ Implicit.new
14
+ end
15
+ end
16
+
17
+ class Implicit
18
+ # Set the base of the implicit wrapping. This should be an existing class.
19
+ def from(starting_class)
20
+ @starting_class = starting_class
21
+ try_to_do_everything
22
+ self
23
+ end
24
+
25
+ # Set the wrapper class. This class must have a constructor which takes one
26
+ # argument, which is an instance of the base class.
27
+ def to(ending_class)
28
+ @ending_class = ending_class
29
+ try_to_do_everything
30
+ self
31
+ end
32
+
33
+ # Set the transformer. This is a Proc which takes an instance of the base
34
+ # class and produces an instance of the wrapper class.
35
+ def via(&transformer)
36
+ @transformer = transformer
37
+ try_to_do_everything
38
+ self
39
+ end
40
+
41
+ def try_to_do_everything
42
+ if !@starting_class.nil? && !@ending_class.nil? && !@transformer.nil?
43
+ transformer = @transformer
44
+ (@ending_class.instance_methods - Object.instance_methods).each do |meth_name|
45
+ @starting_class.class_eval do
46
+ define_method(meth_name) do |*args|
47
+ transformer.call(self).send(meth_name,*args)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ private :try_to_do_everything
54
+ end
@@ -0,0 +1,43 @@
1
+ require 'test/unit'
2
+ require 'implicitly'
3
+
4
+ class FixnumWithTime
5
+ def initialize(n)
6
+ @n = n
7
+ end
8
+
9
+ def minutes
10
+ seconds * 60
11
+ end
12
+
13
+ def hours
14
+ minutes * 60
15
+ end
16
+
17
+ def seconds
18
+ @n
19
+ end
20
+ end
21
+
22
+ class ImplicitlyTest < Test::Unit::TestCase
23
+ implicitly.from(Fixnum).to(FixnumWithTime).via {|n| FixnumWithTime.new(n) }
24
+
25
+ def test_fixnum_with_time
26
+ assert_equal 120, 2.minutes
27
+ assert_equal 7200, 2.hours
28
+ assert_equal 2, 2.seconds
29
+ end
30
+
31
+ def test_fixnum_with_time_delegation
32
+ assert !2.minutes.zero?
33
+ end
34
+ end
35
+
36
+ # TODO:
37
+ #class UnimplicitlyTest < Test::Unit::TestCase
38
+ # def test_fixnum_sans_time
39
+ # assert_raise(NoMethodError) do
40
+ # 2.minutes
41
+ # end
42
+ # end
43
+ #end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: implicitly
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Mike Burns
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-24 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: A port of Scala's implicits, this is an alternative to open classes that allows for easier testing.
22
+ email: mburns@thoughtbot.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - README.rdoc
31
+ - Rakefile
32
+ - lib/implicitly.rb
33
+ - test/test_implicitly.rb
34
+ homepage: http://rubygems.org/gems/implicitly
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.7.2
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Wrap class instances implicitly
67
+ test_files:
68
+ - test/test_implicitly.rb