rint 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a88bdceba9428f2c280c4c402720ec1e64339f50
4
- data.tar.gz: 2c07c6a3ed81db32e97964dbb616581f23f9cd23
3
+ metadata.gz: 94920569dcb0c8f3ceabdadeeae16ad559b7893e
4
+ data.tar.gz: a38868d50fea6d32ec02841aab0c1d6745e90188
5
5
  SHA512:
6
- metadata.gz: 44067cd1e8c048866b797480e638c48dbe5227394b9f12fab6cb24ee5aa4468ecf3fa8abb3eceeba2860d317ba7bfa1c512c4b4fd57201f16adb8910e6aca048
7
- data.tar.gz: afa0e5e6cce4f038b147f47b98b1fc8efff5a2e1960148d041f1e91be77c7bdf06fed91c5686195642b1265a199324211b7337da953951129110374a24e9af7a
6
+ metadata.gz: 5b69a6e1bc56acae37c0d95a1d7ea5ab72e0a7035e8aae42d6fc788388fcdfee41462501b09ca6a5227c5b8f6e1a7caff4a76b0b060311280a53b7d7b330e198
7
+ data.tar.gz: 8466fca69539bec30f10707b03f9d106f2c24b356391597315aaf03605ea34af6ec2c413de47518d3009ee30d4bd9897a02f9af3b7af17f5bce72f8823bd1625
@@ -0,0 +1,29 @@
1
+ # This file is a template, and might need editing before it works on your project.
2
+ # Official language image. Look for the different tagged releases at:
3
+ # https://hub.docker.com/r/library/ruby/tags/
4
+ image: "ruby:2.3"
5
+
6
+ # Pick zero or more services to be used on all builds.
7
+ # Only needed when using a docker container to run your tests in.
8
+ # Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-service
9
+ services:
10
+
11
+ variables:
12
+
13
+ # Cache gems in between builds
14
+ cache:
15
+ paths:
16
+ - vendor/ruby
17
+
18
+ # This is a basic example for a gem or script which doesn't use
19
+ # services such as redis or postgres
20
+ before_script:
21
+ - ruby -v # Print out ruby version for debugging
22
+ # Uncomment next line if your rails app needs a JS runtime:
23
+ # - apt-get update -q && apt-get install nodejs -yqq
24
+ - gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image
25
+ - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby
26
+
27
+ rspec:
28
+ script:
29
+ - rspec spec
@@ -0,0 +1,6 @@
1
+ ## [0.2.0 (unreleased)]
2
+ - Add method arity check to _must_implement_ and refactored specs - @rodrigo-ehresmann
3
+ - Added coverage and build status configuration and badges.
4
+
5
+ ## [0.1.0]
6
+ - Initial implementation, including CLI generator.
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
+ [![Gem Version](https://badge.fury.io/rb/rint.svg)](https://badge.fury.io/rb/rint)
2
+ [![build status](https://gitlab.com/jameslopez/rint/badges/master/build.svg)](https://gitlab.com/jameslopez/rint/commits/master)
3
+ [![coverage report](https://gitlab.com/jameslopez/rint/badges/master/coverage.svg)](https://gitlab.com/jameslopez/rint/commits/master)
4
+
1
5
  # Rint (Ruby Interface)
2
6
 
3
- rint provides a way to implement behaviour defined by Interface files, warning when the desired behaviour is missing.
7
+ Rint provides a way to implement behaviour defined by Interface files, warning when the desired behaviour is missing.
4
8
 
5
9
  ### Example:
6
10
 
@@ -10,55 +14,62 @@ module Playable
10
14
  include Interface
11
15
 
12
16
  def initialize
13
- must_implement :play, :play_quietly
17
+ must_implement :play, play_quietly: 1
14
18
  end
15
19
  end
16
20
 
17
- require 'playable'
18
- class Instrument
21
+ class Instrument
19
22
  implements Playable
20
23
  end
21
24
 
22
- Instrument.new #will throw: Interface::Error::NotImplementedError: Expected Instrument to implement play for interface Playable
25
+ Instrument.new # will throw: Interface::Error::NotImplementedError: Expected Instrument to implement play for interface Playable
23
26
  ```
24
27
 
28
+ As showed in the example above,`must_implement` allows you enforce the implementation of the methods, specifying the arity. When not specified, only the method implementation will be checked.
29
+
25
30
  There is also a CLI to generate the interfaces from the command line:
26
31
  ```sh
27
- $ rint c Playable play play_quietly
32
+ $ rint c Playable play play_quietly:1
28
33
  ```
29
34
  will generate lib/playable.rb (namespaces are also supported).
30
35
 
36
+ ### Installation
37
+
38
+ Add it to your Gemfile:
39
+
40
+ `gem 'rint'`
41
+
42
+ and run
43
+
44
+ ```sh
45
+ $ bundle install
46
+ ```
47
+
31
48
  ### Goals
32
49
 
33
- Duck typing can be evil if not used correctly. While Ruby applications can get a good level of confidence about issues arisen by duck typing, the fear of a method missing exception or constant changes to a class may lead the developer to use safety checks such as respond_to? or raise Errors when a method is missing. This implementation of rint wraps what other static languages use and encapsulates the safety check in a common place, also making explicit the behaviour through the word "implements" and expecting the developer to guess the behaviour of a class without looking at docs or partially implemented code. It also provides a centralised way to implement the interface pattern without having the code throwing an error in a hidden method.
50
+ Duck typing can be evil if not used correctly. While Ruby applications can get a good level of confidence about issues arisen by duck typing, the fear of a method missing exception or constant changes to a class may lead the developer to use safety checks such as respond_to? or raise Errors when a method is missing.
51
+
52
+ This implementation of rint wraps what other static languages use and encapsulates the safety check in a common place, also making explicit the behaviour through the word "implements" and expecting the developer to guess the behaviour of a class without looking at docs or partially implemented code.
34
53
 
35
- ### Version
36
- 0.1.0
54
+ It also provides a centralised way to implement the interface pattern without having the code throwing an error in a hidden method.
37
55
 
38
56
  ### Options
39
57
 
40
- The environment variable DISABLE_RUBY_INTERFACE can be set to 1 in order to globally disable the interfaces - this also means that no Exception will get thrown. This might be particularly useful in production for performance reasons if we are confident enough through tests that the interfaces are all implemented.
58
+ The environment variable DISABLE_RUBY_INTERFACE can be set to 1 in order to globally disable the interfaces - no Error will get thrown. This might be particularly useful in production for performance reasons if we are confident enough through tests that the interfaces are all implemented.
41
59
 
42
- ### Installation
60
+ ### Contributing
43
61
 
44
- Add it to your Gemfile:
62
+ - Fork it
45
63
 
46
- gem 'rint'
64
+ - Create your feature branch (git checkout -b my-new-feature)
47
65
 
48
- and run
66
+ - Commit your changes (git commit -am 'Add some feature')
49
67
 
50
- ```sh
51
- $ bundle install
52
- ```
68
+ - Push to the branch (git push origin my-new-feature)
53
69
 
54
- ### Contributing
70
+ - Create new Pull Request
55
71
 
56
- Fork it
57
- Create your feature branch (git checkout -b my-new-feature)
58
- Commit your changes (git commit -am 'Add some feature')
59
- Push to the branch (git push origin my-new-feature)
60
- Create new Pull Request
61
- Enjoy!
72
+ - Enjoy!
62
73
 
63
74
 
64
75
  License
@@ -35,7 +35,13 @@ class InterfaceGenerator < Thor::Group
35
35
  end
36
36
 
37
37
  def methods
38
- args[2..-1].map { |m| ":#{m}" }.join(', ')
38
+ args[2..-1].map do |m|
39
+ if m.scan(/\d+/).empty?
40
+ ":#{m}"
41
+ else
42
+ m.gsub(":", ": ")
43
+ end
44
+ end.join(", ")
39
45
  end
40
46
 
41
47
  def name
@@ -3,14 +3,15 @@ module Interface
3
3
  # Raised when a method has not been implemented by a class that
4
4
  # has used the implements <InterfaceName> method.
5
5
  class NotImplementedError < NoMethodError
6
- def initialize(class_name:, method_name:, interface_name:)
7
- super(error_message(class_name, method_name, interface_name), method_name)
6
+ def initialize(class_name:, method_name:, method_arity:, interface_name:)
7
+ super(error_message(class_name, method_name, method_arity, interface_name), method_name)
8
8
  end
9
9
 
10
10
  private
11
11
 
12
- def error_message(class_name, method_name, interface_name)
13
- "Expected #{class_name} to implement #{method_name} for interface #{interface_name}"
12
+ def error_message(class_name, method_name, method_arity, interface_name)
13
+ arity = method_arity ? "/#{method_arity}" : ""
14
+ "Expected #{class_name} to implement #{method_name}#{arity} for interface #{interface_name}"
14
15
  end
15
16
  end
16
17
  end
@@ -2,17 +2,47 @@ require 'interface/error/not_implemented_error'
2
2
 
3
3
  module Interface
4
4
  module Helpers
5
- # Errors raised here identify the class_name that is not implementing
6
- # the method required by the Interface.
5
+ # Errors raised here identify the class_name that is not implementing or is
6
+ # implemented with the wrong arity required by the Interface.
7
7
  def must_implement(*args)
8
- args.each do |method_name|
9
- next if respond_to? method_name
10
- raise Interface::Error::NotImplementedError.new(
11
- class_name: self.class.name,
12
- method_name: method_name,
13
- interface_name: self.class.ancestors.first
14
- )
8
+ args.each do |method|
9
+ if method.is_a? Hash
10
+ method.each do |name, arity|
11
+ next if valid_method?(name, arity)
12
+ raise_interface_error(name, arity)
13
+ end
14
+ else
15
+ next if valid_method?(method)
16
+ raise_interface_error(method)
17
+ end
15
18
  end
16
19
  end
20
+
21
+ private
22
+
23
+ def raise_interface_error(method_name, method_arity = nil)
24
+ raise Interface::Error::NotImplementedError.new(
25
+ class_name: self.class.name,
26
+ method_name: method_name,
27
+ method_arity: method_arity,
28
+ interface_name: self.class.ancestors.first
29
+ )
30
+ end
31
+
32
+ # Check if method is implemented and have the specified arity (where nil
33
+ # points to 'unlimited').
34
+ def valid_method?(name, arity = nil)
35
+ respond_to?(name) && expected_arity?(name, arity)
36
+ end
37
+
38
+ def expected_arity?(method, arity)
39
+ return true unless arity
40
+ method_arity(method) == arity
41
+ end
42
+
43
+ # Arity of the implemented method.
44
+ def method_arity(method_name)
45
+ method(method_name).arity.abs
46
+ end
17
47
  end
18
48
  end
@@ -1,3 +1,3 @@
1
1
  module Interface
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -22,5 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'bundler', '~> 1.10'
23
23
  spec.add_development_dependency 'rake', '~> 10.0'
24
24
  spec.add_development_dependency 'rspec', '~> 3.3'
25
+ spec.add_development_dependency 'simplecov', '~> 0.12'
25
26
  spec.add_dependency 'thor', '~> 0.19'
26
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Lopez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-13 00:00:00.000000000 Z
11
+ date: 2016-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.12'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: thor
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -75,8 +89,10 @@ extensions: []
75
89
  extra_rdoc_files: []
76
90
  files:
77
91
  - ".gitignore"
92
+ - ".gitlab-ci.yml"
78
93
  - ".rspec"
79
94
  - ".travis.yml"
95
+ - CHANGELOG.md
80
96
  - Gemfile
81
97
  - LICENSE
82
98
  - README.md
@@ -110,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
126
  version: '0'
111
127
  requirements: []
112
128
  rubyforge_project:
113
- rubygems_version: 2.4.8
129
+ rubygems_version: 2.5.1
114
130
  signing_key:
115
131
  specification_version: 4
116
132
  summary: Ruby interfaces made simple