ruby_interface 0.1.0 → 0.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +23 -5
- data/lib/ruby_interface/version.rb +1 -1
- data/lib/ruby_interface.rb +38 -9
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9b8ffa291917e451bb903aef5276f566b7294f1
|
4
|
+
data.tar.gz: 87b777bdd6a33288a62a1e15675ea6e816fdf3f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ea17d4036a0ebd057ec6d9d632f8dbcc8f568e94db4ce5cbb152e0bb36ea4626a3cb2e597c260ee48489f99ed34370046b686a5bee762afac3611ff625cfdc7
|
7
|
+
data.tar.gz: 1ffdcb7225e371e5cf7300ef7b1e7e88ba50929962a8cfdca61ecde77f6b0be13489cca1dee61c3c7885556443d6ad9550be33ae454fc7fe032c762ab4d52f5e
|
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
When a class is interpreted and does not have the required methods, it throws an error.
|
4
4
|
|
5
5
|
Caveats:
|
6
|
-
-
|
6
|
+
- Creating anonymous classes requires the user to use `class_eval` to define methods.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -23,6 +23,8 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
+
### Named Classes
|
27
|
+
|
26
28
|
```ruby
|
27
29
|
class SpaceShip
|
28
30
|
include RubyInterface
|
@@ -35,15 +37,31 @@ end
|
|
35
37
|
# => NotImplementedError, 'Expected Enterprise to define #engine, #computer'
|
36
38
|
```
|
37
39
|
|
40
|
+
If a class is redefined, the presence of required methods will not be checked.
|
41
|
+
|
42
|
+
### Anonymous classes
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class SpaceShip
|
46
|
+
include RubyInterface
|
47
|
+
|
48
|
+
defines :engine, :computer
|
49
|
+
end
|
50
|
+
|
51
|
+
space_ship = Class.new(SpaceShip)
|
52
|
+
space_ship.class_eval { }
|
53
|
+
# => NotImplementedError, 'Expected Enterprise to define #engine, #computer'
|
54
|
+
```
|
55
|
+
|
56
|
+
After the first `class_eval`, the rest of the calls to it will not check whether methods are defined.
|
57
|
+
Unfortunately, right now, `class_eval` has to be called to check whether the methods are defined,
|
58
|
+
pending resolution of https://bugs.ruby-lang.org/issues/12696.
|
59
|
+
|
38
60
|
## Development
|
39
61
|
|
40
62
|
After checking out the repo, run `bin/setup` to install dependencies.
|
41
63
|
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
42
64
|
|
43
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
44
|
-
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
|
45
|
-
which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
46
|
-
|
47
65
|
## Contributing
|
48
66
|
|
49
67
|
Bug reports and pull requests are welcome on GitHub at https://github.com/kklimuk/ruby_interface.
|
data/lib/ruby_interface.rb
CHANGED
@@ -4,6 +4,15 @@ require 'awesome_print'
|
|
4
4
|
module RubyInterface
|
5
5
|
def self.included(klass)
|
6
6
|
klass.extend ClassMethods
|
7
|
+
|
8
|
+
klass.class_eval do
|
9
|
+
singleton_class.send(:alias_method, :_old_inherited, :inherited) if respond_to?(:inherited)
|
10
|
+
end
|
11
|
+
|
12
|
+
def klass.inherited(child)
|
13
|
+
child.name.nil? ? anonymous_class_definition(child) : named_class_definition(child)
|
14
|
+
_old_inherited(child) if respond_to?(:_old_inherited)
|
15
|
+
end
|
7
16
|
end
|
8
17
|
|
9
18
|
module ClassMethods
|
@@ -12,17 +21,37 @@ module RubyInterface
|
|
12
21
|
@methods_to_define += args
|
13
22
|
end
|
14
23
|
|
15
|
-
def
|
16
|
-
|
17
|
-
next unless point.self == klass
|
18
|
-
missing_methods = @methods_to_define - klass.instance_methods(false)
|
19
|
-
trace.disable
|
24
|
+
def track_required_methods(child)
|
25
|
+
missing_methods = @methods_to_define - child.instance_methods(false)
|
20
26
|
|
21
|
-
|
27
|
+
return if missing_methods.empty?
|
28
|
+
|
29
|
+
message = "Expected #{child.name || 'anonymous class'} to define "
|
30
|
+
message << missing_methods.map { |method| "##{method}" }.join(', ')
|
31
|
+
raise NotImplementedError, message
|
32
|
+
end
|
22
33
|
|
23
|
-
|
24
|
-
|
25
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
def anonymous_class_definition(child)
|
37
|
+
klass = self
|
38
|
+
[:class_exec, :class_eval].each do |method|
|
39
|
+
old_method = "_old_#{method}".to_sym
|
40
|
+
child.singleton_class.send(:alias_method, old_method, method)
|
41
|
+
|
42
|
+
child.define_singleton_method method do |*args, &block|
|
43
|
+
send old_method, *args, &block
|
44
|
+
klass.track_required_methods(child)
|
45
|
+
child.singleton_class.send(:alias_method, method, old_method)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def named_class_definition(child)
|
51
|
+
trace = TracePoint.new(:end) do |point|
|
52
|
+
next unless point.self == child
|
53
|
+
trace.disable
|
54
|
+
track_required_methods child
|
26
55
|
end
|
27
56
|
trace.enable
|
28
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_interface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kirill Klimuk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- ".ruby-gemset"
|
79
79
|
- ".ruby-version"
|
80
80
|
- ".travis.yml"
|
81
|
+
- CHANGELOG.md
|
81
82
|
- Gemfile
|
82
83
|
- Gemfile.lock
|
83
84
|
- LICENSE.txt
|