shuber-interface 0.0.2 → 0.0.3

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.
data/README.rdoc CHANGED
@@ -41,8 +41,10 @@ Then use the <tt>implements</tt> method in your classes (also aliased as <tt>imp
41
41
  method == :off ? @power = false : super
42
42
  end
43
43
 
44
+ # Use this whenever you have custom method_missing logic
45
+ # See http://www.ruby-doc.org/core/classes/Object.html#M001006
44
46
  def respond_to_missing?(method, include_private)
45
- method == :off
47
+ method == :off || super
46
48
  end
47
49
  end
48
50
 
@@ -80,7 +82,55 @@ You can also explicitly list <tt>interfaces</tt> to test
80
82
  end
81
83
  end
82
84
 
83
- == Note on Patches/Pull Requests
85
+
86
+ == Why would you ever want to use this?
87
+
88
+ It's useful for when you're working with libraries that have extensible APIs, like {writing custom ActiveModel compliant models}[http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/]
89
+
90
+ Imagine if we defined <tt>ActiveModel</tt> with something like
91
+
92
+ module ActiveModel
93
+ # checks if this object has been saved
94
+ def new_record?
95
+ end
96
+
97
+ # checks if this object is valid
98
+ def valid?
99
+ end
100
+
101
+ # and the rest of the methods...
102
+ end
103
+
104
+ We'd have a nice clear view of exactly which methods our custom implementations need to define AND one centralized place for documentation
105
+
106
+ Now we can define our custom implementation
107
+
108
+ class CompliantModel
109
+ implements ActiveModel
110
+
111
+ def valid?
112
+ true
113
+ end
114
+ end
115
+
116
+ Then we can easily test if we've completely implemented <tt>ActiveModel</tt> (or are missing any new methods because <tt>ActiveModel</tt> was updated)
117
+
118
+ require 'test/unit'
119
+
120
+ Test::Unit::TestCase.send(:include, Interface::TestHelper)
121
+
122
+ class CompliantModelTest < Test::Unit::TestCase
123
+ def test_should_implement_active_model
124
+ assert_implements_interface CompliantModel.new, ActiveModel # Failure: unimplemented interface methods for CompliantModel: {ActiveModel=>["new_record?"]}
125
+ end
126
+ end
127
+
128
+ <tt>ActiveModel</tt> actually already has a great solution for this problem (providing a module called <tt>ActiveModel::Lint::Tests</tt> that you can include into your test cases to test compliance with the API) but it's still a good example for demonstrating this gem's usefulness
129
+
130
+ You can see this gem used in {shuber/nestable}[https://github.com/shuber/nestable] which is actually why I created it
131
+
132
+
133
+ == Patches and pull requests
84
134
 
85
135
  * Fork the project.
86
136
  * Make your feature addition or bug fix.
@@ -4,9 +4,9 @@ module Interface
4
4
  def self.extended(base) # :nodoc:
5
5
  base.class_eval do
6
6
  instance_methods(false).each do |method|
7
- define_method(method) do |*args|
7
+ define_method(method) do |*args, &block|
8
8
  begin
9
- method_missing(method.to_sym, *args)
9
+ method_missing(method.to_sym, *args, &block)
10
10
  rescue NoMethodError
11
11
  raise NotImplementedError.new("#{self.class} needs to implement '#{method}' for interface #{base}")
12
12
  end
@@ -1,7 +1,7 @@
1
1
  module Interface
2
2
  # Contains interface testing methods to include in your test framework
3
3
  module TestHelper
4
- # Raises AssertionFailedError if <tt>object</tt> does not implement all methods from <tt>interfaces</tt>
4
+ # Raises <tt>AssertionFailedError</tt> if <tt>object</tt> does not implement all methods from <tt>interfaces</tt>
5
5
  #
6
6
  # <tt>interfaces</tt> defaults to <tt>object.interfaces</tt> if none are specified
7
7
  #
@@ -3,7 +3,7 @@ module Interface
3
3
  module Version
4
4
  MAJOR = 0
5
5
  MINOR = 0
6
- PATCH = 2
6
+ PATCH = 3
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
data/lib/interface.rb CHANGED
@@ -47,9 +47,21 @@ module Interface
47
47
  def unimplemented_methods_for(interface)
48
48
  interface.instance_methods(false).reject do |method|
49
49
  method = method.to_sym
50
- (respond_to?(method, true) && self.method(method).owner != interface) || (respond_to?(:respond_to_missing?, true) && respond_to_missing?(method, true))
50
+ (respond_to?(method, true) && self.method(method).owner != interface) || respond_to_missing?(method, true)
51
51
  end.sort
52
52
  end
53
+
54
+ # <tt>Object#respond_to_missing?</tt> wasn't implemented until ruby version 1.9
55
+ unless respond_to?(:respond_to_missing?)
56
+ def respond_to?(method, include_private = false) # :nodoc:
57
+ super || respond_to_missing?(method, include_private)
58
+ end
59
+
60
+ def respond_to_missing?(method, include_private) # :nodoc:
61
+ false
62
+ end
63
+ end
64
+
53
65
  end
54
66
 
55
67
  Object.send(:include, Interface)
@@ -27,7 +27,7 @@ class Device < BrokenDevice
27
27
  end
28
28
 
29
29
  def respond_to_missing?(method, include_private)
30
- method == :off
30
+ method == :off || super
31
31
  end
32
32
  end
33
33
 
@@ -83,4 +83,8 @@ class InterfaceTest < Test::Unit::TestCase
83
83
  assert_raises(Test::Unit::AssertionFailedError) { assert_implements_interface BrokenDevice.new, Remote }
84
84
  end
85
85
 
86
+ def test_should_respond_to_respond_to_missing
87
+ assert respond_to?(:respond_to_missing?)
88
+ end
89
+
86
90
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shuber-interface
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sean Huber
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-09 00:00:00 -08:00
18
+ date: 2011-02-10 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies: []
21
21