bound 1.0.0 → 1.0.1

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: 55ee3700c0f6aff1e212a4b05a2d1c7eab87b9f7
4
- data.tar.gz: 2a50137771a1b061051f14c46dd7b1ec8cd3ec95
3
+ metadata.gz: 40eb13fe1d57fd0d42c0d0fc5c91348173071cb2
4
+ data.tar.gz: 61658fd50d9bf0dd3790b75bca0588e80863ca4f
5
5
  SHA512:
6
- metadata.gz: aa4817e8a7046bb2d5e56da17a466968061497b036109057037e8f747c32332b25b4f247a3e0202ada60dc4555d78a92561adec5564b88c63294977da5f50f62
7
- data.tar.gz: 804361979bd44ff9a1a42cb18e08300ae6169a518f9b3e5f2be387b7f1a9169f80356386afb800bb44c692f9a55e7cb36e9199be45add2dae642a9d1384cdff6
6
+ metadata.gz: 86f3b026b006ff92b6652cd3e37df15206bcb304150c4d9c3c0fee70809b02a65fce814f67dc92f40e4df87ef93e351b182420e38d968e8c8cac27e8fbe8b9c5
7
+ data.tar.gz: ebc0035cc9f636a9af6f798a3cb70ab0420834f73b8212b2f42d74b640217a6ebb5385b7e3e98830c42f6cbe0282757f2839e55a44d0c55b4d0167437177afd7
@@ -4,7 +4,6 @@ rvm:
4
4
  - 1.9.3
5
5
  - jruby-18mode # JRuby in 1.8 mode
6
6
  - jruby-19mode # JRuby in 1.9 mode
7
- - rbx-18mode
8
- - rbx-19mode
7
+ - rbx
9
8
  - 1.8.7
10
9
  - ree
data/README.md CHANGED
@@ -2,7 +2,19 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/neopoly/bound.png)](https://travis-ci.org/neopoly/bound) [![Gem Version](https://badge.fury.io/rb/bound.png)](http://badge.fury.io/rb/bound) [![Code Climate](https://codeclimate.com/github/neopoly/bound.png)](https://codeclimate.com/github/neopoly/bound)
4
4
 
5
- TODO: Write a gem description
5
+ **In short:** The mission: Bring the notion of interfaces to ruby.
6
+
7
+ **More detailed:** When you build separated or distributed architectures in ruby,
8
+ you probably encountered the problem of stale mocks or wrongly mocked interfaces
9
+ of specific services at the boundaries of the different domains.
10
+
11
+ To tackle this problem, we use `Bound`. Instead of providing just a list of
12
+ arguments to a poor little boundary method, it will just accept an argument, its
13
+ request, to speak in more technical terms. By implementing the request and
14
+ response objects through `Bound`, you get validated interfaces and more explicit
15
+ and self documenting code for free.
16
+
17
+ See **Usage** below for more details with a concrete example.
6
18
 
7
19
  ## Installation
8
20
 
@@ -20,7 +32,90 @@ Or install it yourself as:
20
32
 
21
33
  ## Usage
22
34
 
23
- TODO: Write usage instructions here
35
+ Consider the folowing scenario:
36
+
37
+ A generic domain which is responsible for administration and management of user
38
+ registrations:
39
+
40
+ ```ruby
41
+ module UserDesk
42
+ end
43
+ ```
44
+
45
+ It will somehow provide access to a registration service which gives you the
46
+ possibility to create new user accounts:
47
+
48
+ ```ruby
49
+ class UserDesk::RegistrationService
50
+ def register_account(email, password)
51
+ ensure_validity!(email)
52
+ user_uid = do_things_on_a_magical_repository(email, password)
53
+
54
+ user_uid
55
+ end
56
+
57
+ private
58
+ # ...
59
+ end
60
+ ```
61
+
62
+ Since the scope of this service can (and will) be very large, it will be painful
63
+ to provide consistency around the different other domains, which get an instance
64
+ of the registration service injected. Especially order changes in a larger
65
+ argument list or added optional arguments could lead to false passing tests and
66
+ therefor probably runtime bugs.
67
+
68
+ By utilizing `Bound`, you could implement this service like following:
69
+
70
+ ```ruby
71
+ class UserDesk::RegistrationService
72
+ Registration = Bound.required(
73
+ :email,
74
+ :password
75
+ )
76
+
77
+ SuccessfulRegistration = Bound.required(:user_uid)
78
+
79
+ def register_account(registration)
80
+ ensure_validity!(registration.email)
81
+ user_uid = do_things_on_a_magical_repository(
82
+ registration.email,
83
+ registration.password
84
+ )
85
+
86
+ SuccessfulRegistration.new(:user_uid => user_uid)
87
+ end
88
+
89
+ private
90
+ # ...
91
+ end
92
+ ```
93
+
94
+ The consumer would now instanciate the boundary class instead of just
95
+ passing arbitrary arguments to the service:
96
+
97
+ ```ruby
98
+ registration = UserDesk::RegistrationService::Registration.new(
99
+ :email => params[:email],
100
+ :password => params[:password]
101
+ )
102
+
103
+ result = registration_service.register_account(registration)
104
+
105
+ do_stuff_with(result.user_uid)
106
+ ```
107
+
108
+ Side note: the `Registration` bound here would also accept any `Object`, which provides the
109
+ methods `email` and `password`.
110
+
111
+ Bound would also loudly fail, if one of the required arguments is omitted or a
112
+ unknown argument is provided. (Specific additional features like nested and
113
+ optional arguments can be seen in the specs).
114
+
115
+ By concretinzing the boundaries, the overall structure of your architecture will
116
+ become more rigid and solid. The mocking part on the consumer-side would only
117
+ occur for the actual `register_account` call, which is fairly trivial now from
118
+ the perspective of boundaries (known object in, known object out).
24
119
 
25
120
  ## Contributing
26
121
 
@@ -241,6 +241,14 @@ class Bound
241
241
  attribute
242
242
  end
243
243
 
244
+ def ==(other)
245
+ return false unless other
246
+
247
+ get_attributes.all? do |attribute|
248
+ attribute.value == other.public_send(attribute.name)
249
+ end
250
+ end
251
+
244
252
  private
245
253
 
246
254
  def validate!
@@ -1,3 +1,3 @@
1
1
  class Bound
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -63,6 +63,32 @@ describe Bound do
63
63
  assert_includes user.get_attributes.map(&:name), :age
64
64
  end
65
65
 
66
+ describe 'equality' do
67
+ let(:user) { User.new(hash) }
68
+
69
+ it 'is given if all the attributes are same' do
70
+ reference_user = User.new(hash)
71
+
72
+ assert_equal user, reference_user
73
+ end
74
+
75
+ it 'is not given if attributes differ' do
76
+ reference_user = User.new(hash.merge(:name => 'DIFF'))
77
+
78
+ refute_equal user, reference_user
79
+ end
80
+
81
+ it 'is given for other objects with same signature' do
82
+ reference_user = Struct.new(:name, :age).new(user.name, user.age)
83
+
84
+ assert_equal user, reference_user
85
+ end
86
+
87
+ it 'is not given for nil' do
88
+ refute_equal user, nil
89
+ end
90
+ end
91
+
66
92
  describe 'wrong initialization' do
67
93
  it 'fails if new is not called with symbols' do
68
94
  assert_raises ArgumentError do
@@ -221,6 +247,20 @@ describe Bound do
221
247
  end
222
248
  end
223
249
 
250
+ describe 'equality' do
251
+ let(:user) { BloggingUser.new(hash) }
252
+ it 'is given if the nested attributes are equal' do
253
+ assert_equal BloggingUser.new(hash), user
254
+ end
255
+
256
+ it 'is not given if nested attributes differ' do
257
+ second_hash = Marshal.load(Marshal.dump hash)
258
+ second_hash[:posts][0][:title] = 'DIFFERENT'
259
+
260
+ refute_equal BloggingUser.new(second_hash), user
261
+ end
262
+ end
263
+
224
264
  it 'fails if posts is no array' do
225
265
  hash[:posts] = {:title => 'broken'}
226
266
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bound
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakob Holderbaum
@@ -9,62 +9,62 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-24 00:00:00.000000000 Z
12
+ date: 2014-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.3'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ~>
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.3'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: minitest
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ~>
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
48
  version: 5.0.7
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ~>
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: 5.0.7
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: simplecov
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  description:
@@ -75,8 +75,8 @@ executables: []
75
75
  extensions: []
76
76
  extra_rdoc_files: []
77
77
  files:
78
- - .gitignore
79
- - .travis.yml
78
+ - ".gitignore"
79
+ - ".travis.yml"
80
80
  - Gemfile
81
81
  - LICENSE.txt
82
82
  - README.md
@@ -99,17 +99,17 @@ require_paths:
99
99
  - lib
100
100
  required_ruby_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - '>='
102
+ - - ">="
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - '>='
107
+ - - ">="
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
111
  rubyforge_project:
112
- rubygems_version: 2.1.11
112
+ rubygems_version: 2.2.2
113
113
  signing_key:
114
114
  specification_version: 4
115
115
  summary: Implements a nice helper for fast boundary definitions