proto_cat 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: de9f7f1818b3b4933f146410674db48dd5c7558a
4
+ data.tar.gz: 762b11e6b470e752bc7ec33565ae7ca73aeeabc7
5
+ SHA512:
6
+ metadata.gz: 528c23d41c529519067c325e1c8e0a4e9d13be9c397eaec0d0485c8ab9ade9938c05b287e2ec07f23079e00a7f960198f8eb95dff77b885f5e9a37c1204dff61
7
+ data.tar.gz: 7c8347bd1e13ebb1d94bebddda82406c69d8f4bc21c1a7aaa442fae4dc0b34baacdca7143104152eb8e4291b8bbd25872a6950ef7d00c36ca594c5d9738c2062
@@ -0,0 +1,16 @@
1
+ coverage
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in proto_cat.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Mohammad Satrio
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # ProtoCat
2
+
3
+ Protocol/Interface for Ruby
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'proto_cat'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install proto_cat
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions. For now you can see the specs for how to use it.
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/tyok/proto_cat/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,15 @@
1
+ require_relative('proto_cat/protocol_module')
2
+ require_relative('proto_cat/object')
3
+
4
+ module ProtoCat
5
+ extend self
6
+
7
+ def define_protocol(&block)
8
+ ProtocolModule.new(&block)
9
+ end
10
+
11
+ def object(obj)
12
+ Object.new(obj)
13
+ end
14
+
15
+ end
@@ -0,0 +1,22 @@
1
+ module ProtoCat
2
+ class NotImplementedError < StandardError
3
+
4
+ attr_reader :protocol, :object
5
+
6
+ def initialize(protocol, object)
7
+ @protocol = protocol
8
+ @object = object
9
+
10
+ super(not_implemented_message)
11
+ end
12
+
13
+ def not_implemented_message
14
+ "#{protocol} is not implemented properly on #{object}: #{failure_string}"
15
+ end
16
+
17
+ def failure_string
18
+ protocol.failure_strings(object).join('\n')
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module ProtoCat
2
+ class Object
3
+
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+
8
+ def satisfy?(protocol)
9
+ protocol.satisfied_by?(@object)
10
+ end
11
+
12
+ def satisfy!(protocol)
13
+ protocol.satisfied_by!(@object)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'error/not_implemented_error'
2
+
3
+ module ProtoCat
4
+ class Protocol
5
+
6
+ def initialize(mod, criteria)
7
+ @module = mod
8
+ @criteria = criteria
9
+ end
10
+
11
+ def satisfied_by!(object)
12
+ satisfied_by?(object) or raise NotImplementedError.new(self, object)
13
+ end
14
+
15
+ def satisfied_by?(object)
16
+ @criteria.all? {|crit| crit.satisfied_by?(object) }
17
+ end
18
+
19
+ def failed_criteria(object)
20
+ @criteria.reject {|crit| crit.satisfied_by?(object) }
21
+ end
22
+
23
+ def failure_strings(object)
24
+ failed_criteria(object).map(&:failure_string)
25
+ end
26
+
27
+ def to_s
28
+ @module.to_s
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'protocol_method'
2
+
3
+ module ProtoCat
4
+ class ProtocolBuilder
5
+
6
+ attr_reader :criteria
7
+
8
+ def initialize
9
+ @criteria = []
10
+ end
11
+
12
+ def has_method(*args)
13
+ @criteria.push(ProtocolMethod.new(*args))
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module ProtoCat
2
+ class ProtocolMethod
3
+
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def satisfied_by?(object)
11
+ object.methods.include?(name)
12
+ end
13
+
14
+ def failure_string
15
+ "#{name} not found"
16
+ end
17
+
18
+ alias_method :to_s, :name
19
+
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ require 'forwardable'
2
+ require_relative 'protocol'
3
+ require_relative 'protocol_builder'
4
+
5
+ module ProtoCat
6
+ class ProtocolModule < Module
7
+ extend Forwardable
8
+
9
+ def_delegators :protocol, :satisfied_by?, :satisfied_by!
10
+ attr_reader :protocol
11
+
12
+ def initialize(&block)
13
+ builder = ProtocolBuilder.new
14
+ block.call(builder)
15
+ @protocol = Protocol.new(self, builder.criteria)
16
+ end
17
+
18
+ def included(klass)
19
+ protocol.satisfied_by!(Class.new(klass))
20
+ end
21
+
22
+ def extended(obj)
23
+ protocol.satisfied_by!(obj)
24
+ end
25
+
26
+ Class = Struct.new(:object) do
27
+ extend Forwardable
28
+ def_delegator :object, :instance_methods, :methods
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module ProtoCat
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'forwardable'
2
+ require_relative('../proto_cat')
3
+
4
+ module ProtoCat
5
+
6
+ class ProtocolModule
7
+ extend Forwardable
8
+ def_delegators :protocol, :===, :must
9
+ end
10
+
11
+ class Protocol
12
+
13
+ alias_method :===, :satisfied_by?
14
+
15
+ def must
16
+ Enforcer.new(self)
17
+ end
18
+
19
+ Enforcer = Struct.new(:protocol) do
20
+ extend Forwardable
21
+ def_delegator :protocol, :satisfied_by!, :===
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'proto_cat/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "proto_cat"
8
+ spec.version = ProtoCat::VERSION
9
+ spec.authors = ["Mohammad Satrio"]
10
+ spec.email = ["wolfaeon@gmail.com"]
11
+ spec.summary = %q{Protocol/Interface for Ruby}
12
+ # spec.description = %q{}
13
+ spec.homepage = "https://github.com/tyok/proto_cat"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.1"
24
+ end
@@ -0,0 +1,107 @@
1
+ require 'ostruct'
2
+ require_relative 'spec_helper'
3
+ require_relative '../lib/proto_cat'
4
+
5
+ RSpec.describe ProtoCat do
6
+
7
+ before do
8
+ IsCat ||= ProtoCat.define_protocol do |p|
9
+ p.has_method(:meow)
10
+ p.has_method(:leg)
11
+ end
12
+
13
+ @cat = OpenStruct.new(meow: 'meow', leg: 4)
14
+ @dog = OpenStruct.new(bark: 'bark', leg: 4)
15
+ end
16
+
17
+ describe 'Protocol' do
18
+
19
+ describe '#satisfied_by?' do
20
+
21
+ it 'returns true when the protocol is satisfied' do
22
+ expect( IsCat.satisfied_by? @cat ).to eq(true)
23
+ expect( IsCat.satisfied_by? @dog ).to eq(false)
24
+ end
25
+
26
+ end
27
+
28
+ describe '#satisfied_by!' do
29
+
30
+ it 'raise error when the protocol is not satisfied' do
31
+ expect( IsCat.satisfied_by! @cat ).to eq(true)
32
+ expect{ IsCat.satisfied_by! @dog }.to raise_error(ProtoCat::NotImplementedError)
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ describe 'Object' do
40
+
41
+ describe '#satisfy?' do
42
+
43
+ it 'returns true when the object satisfies the protocol' do
44
+ expect( ProtoCat.object(@cat).satisfy? IsCat ).to eq(true)
45
+ expect( ProtoCat.object(@dog).satisfy? IsCat ).to eq(false)
46
+ end
47
+
48
+ end
49
+
50
+ describe '#satisfy!' do
51
+
52
+ it 'raise error when the object doesn\'t satisfy the protocol' do
53
+ expect( ProtoCat.object(@cat).satisfy! IsCat ).to eq(true)
54
+ expect{ ProtoCat.object(@dog).satisfy! IsCat }.to raise_error(ProtoCat::NotImplementedError)
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ describe 'Module' do
62
+
63
+ it 'doesn\'t raise error when the including class satisfies the protocol' do
64
+ define_class = proc do
65
+
66
+ cat_class = Class.new do
67
+ def meow
68
+ 'meow'
69
+ end
70
+
71
+ def leg
72
+ 4
73
+ end
74
+ end
75
+ cat_class.include(IsCat)
76
+
77
+ end
78
+
79
+ expect(&define_class).not_to raise_error
80
+ end
81
+
82
+ it 'raises error when the including class doesn\'t satisfy the protocol' do
83
+ define_class = proc do
84
+
85
+ cat_class = Class.new do
86
+ def meow
87
+ 'meow'
88
+ end
89
+ end
90
+ cat_class.include(IsCat)
91
+
92
+ end
93
+
94
+ expect(&define_class).to raise_error(ProtoCat::NotImplementedError)
95
+ end
96
+
97
+ it 'doesn\'t raise error when the extending object satisfies the protocol' do
98
+ expect{ @cat.extend(IsCat) }.not_to raise_error
99
+ end
100
+
101
+ it 'raises error when the extending object doesn\'t satisfy the protocol' do
102
+ expect{ @dog.extend(IsCat) }.to raise_error(ProtoCat::NotImplementedError)
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,5 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
@@ -0,0 +1,29 @@
1
+ require 'ostruct'
2
+ require_relative 'spec_helper'
3
+ require_relative '../lib/proto_cat/with_sugar'
4
+
5
+ RSpec.describe ProtoCat do
6
+ before do
7
+ IsCat ||= ProtoCat.define_protocol do |p|
8
+ p.has_method(:meow)
9
+ p.has_method(:leg)
10
+ end
11
+
12
+ @cat = OpenStruct.new(meow: 'meow', leg: 4)
13
+ @dog = OpenStruct.new(bark: 'bark', leg: 4)
14
+ end
15
+
16
+ describe '===' do
17
+ it 'behaves like #satisfied_by?' do
18
+ expect( IsCat === @cat ).to eq(true)
19
+ expect( IsCat === @dog ).to eq(false)
20
+ end
21
+ end
22
+
23
+ describe 'must ===' do
24
+ it 'behaves like #satisfied_by!' do
25
+ expect( IsCat.must === @cat ).to eq(true)
26
+ expect{ IsCat.must === @dog }.to raise_error(ProtoCat::NotImplementedError)
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: proto_cat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mohammad Satrio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ description:
56
+ email:
57
+ - wolfaeon@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/proto_cat.rb
68
+ - lib/proto_cat/error/not_implemented_error.rb
69
+ - lib/proto_cat/object.rb
70
+ - lib/proto_cat/protocol.rb
71
+ - lib/proto_cat/protocol_builder.rb
72
+ - lib/proto_cat/protocol_method.rb
73
+ - lib/proto_cat/protocol_module.rb
74
+ - lib/proto_cat/version.rb
75
+ - lib/proto_cat/with_sugar.rb
76
+ - proto_cat.gemspec
77
+ - spec/proto_cat_spec.rb
78
+ - spec/spec_helper.rb
79
+ - spec/sugar_spec.rb
80
+ homepage: https://github.com/tyok/proto_cat
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.4.1
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Protocol/Interface for Ruby
104
+ test_files:
105
+ - spec/proto_cat_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/sugar_spec.rb
108
+ has_rdoc: