bound 1.0.0 → 1.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.
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