red_bikini 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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require ./lib/red_bikini
2
+ --require ./spec/person
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - rbx-19mode
6
+ - jruby-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in red_bikini.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ red_bikini (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.4)
10
+ rake (10.1.0)
11
+ rspec (2.14.1)
12
+ rspec-core (~> 2.14.0)
13
+ rspec-expectations (~> 2.14.0)
14
+ rspec-mocks (~> 2.14.0)
15
+ rspec-core (2.14.4)
16
+ rspec-expectations (2.14.1)
17
+ diff-lcs (>= 1.1.3, < 2.0)
18
+ rspec-mocks (2.14.3)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (~> 1.3)
25
+ rake
26
+ red_bikini!
27
+ rspec (~> 2.14)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Titov Andrey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ [![Build Status](https://travis-ci.org/idrozd/red_bikini.png?branch=master)](https://travis-ci.org/idrozd/red_bikini)
2
+
3
+ # What is this?
4
+ Something you come up with when you know a little ruby and words `public_exec` stuck in your head for a couple days:
5
+ `instance_exec` on wrapper around receiver to conceal private methods, with aliased setters
6
+
7
+ ### cat spec/show_off_spec.rb
8
+ ```ruby
9
+ describe RedBikini do
10
+
11
+ before{RedBikini.add_to_wardrobe! Person}
12
+
13
+ example 'punchline', contrived: true do
14
+ time = '17:00'
15
+
16
+ expect("Tom, Gia and 'Happy' Mike are heading to the cinema at 17:00").to eq(
17
+ Person.such_that do
18
+ name_is 'Mike'
19
+ friends_are %w[Tom Gia]
20
+ set_nickname 'Happy'
21
+ end.confide('the cinema') do |where|
22
+ "#{friends * ', '} and '#{nickname}' #{name} are heading to #{where} at #{time}"
23
+ end
24
+ )
25
+
26
+ end
27
+
28
+ describe 'access' do
29
+ let(:josephine){ Person.new(1,'Josephine')}
30
+ specify do
31
+ expect{josephine.tell{credit_card_number}}
32
+ .to raise_error NoMethodError # private
33
+ end
34
+ specify do
35
+ expect{josephine.expose{girly_secrets}}
36
+ .to raise_error NoMethodError # protected
37
+ end
38
+ end
39
+
40
+ describe 'Kernel#which' do
41
+ example :even_more_contrived do
42
+ [Person.new(nil, 'George'),
43
+ Person.new(nil, 'Kevin' ),
44
+ Person.new(nil, 'Steven'),
45
+ Person.new(22)].
46
+
47
+ find_all(&which{name and name =~ /ev/}).
48
+
49
+ map(&:name).
50
+ should eq %w[Kevin Steven]
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ ```
57
+ ### cat spec/person.rb
58
+ ```ruby
59
+ Person = Struct.new(:id, :name, :friends, :nickname) do
60
+ OWN_CONST = 'Person const'
61
+ def === other
62
+ other.respond_to? :id and id == other.id
63
+ end
64
+ private
65
+ def credit_card_number
66
+ 'meh'
67
+ end
68
+ protected
69
+ def girly_secrets
70
+ 'nah'
71
+ end
72
+ end
73
+
74
+ ```
75
+
76
+ ### Red Bikini?
77
+ Red for ruby, bikini for informal communication
78
+ Think of objects in bikini
79
+
80
+ ### Why?
81
+ It just would not let me go
82
+
83
+ ### So...
84
+ You probably shouldn't use this for serious things, but I wouldn't discourage you from it of course.
85
+ Some kind of DSL sounds as a candidate topic.
86
+
87
+ Check out other specs for gotchas.
88
+ I would note that inside it uses instance exec applied to a wrapper around
89
+ reciever, so it wouldn`t bind calling context methods (which is good),
90
+ but binds locals and constants.
91
+ - Also, or/equal (`||=`) won't work directly without specifiyng explicit receiver of course (`self.attr ||=` will work)
92
+ - Also, `self` wouldn't work with `case` operator - I don't want to hack reciever class `.===` just for that.
93
+ Although, you may use `_self` for this (original object).
94
+
95
+
96
+ - [spec/closure_binding_spec.rb](spec/closure_binding_spec.rb)
97
+
98
+ - [spec/typing_spec.rb](spec/typing_spec.rb)
99
+
100
+ - [spec/operators_spec.rb](spec/operators_spec.rb)
101
+
102
+ - [spec/aliases_spec.rb](spec/aliases_spec.rb)
103
+
104
+ - [spec/collisions_spec.rb](spec/collisions_spec.rb)
105
+
data/README.md.erb ADDED
@@ -0,0 +1,37 @@
1
+ [![Build Status](https://travis-ci.org/idrozd/red_bikini.png?branch=master)](https://travis-ci.org/idrozd/red_bikini)
2
+
3
+ # What is this?
4
+ Something you come up with when you know a little ruby and words `public_exec` stuck in your head for a couple days:
5
+ `instance_exec` on wrapper around receiver to conceal private methods, with aliased setters
6
+
7
+ ### <%= c = "cat spec/show_off_spec.rb" %>
8
+ ```ruby
9
+ <%= `#{c}` %>
10
+ ```
11
+ ### <%= c = "cat spec/person.rb" %>
12
+ ```ruby
13
+ <%= `#{c}`%>
14
+ ```
15
+
16
+ ### Red Bikini?
17
+ Red for ruby, bikini for informal communication
18
+ Think of objects in bikini
19
+
20
+ ### Why?
21
+ It just would not let me go
22
+
23
+ ### So...
24
+ You probably shouldn't use this for serious things, but I wouldn't discourage you from it of course.
25
+ Some kind of DSL sounds as a candidate topic.
26
+
27
+ Check out other specs for gotchas.
28
+ I would note that inside it uses instance exec applied to a wrapper around
29
+ reciever, so it wouldn`t bind calling context methods (which is good),
30
+ but binds locals and constants.
31
+ - Also, or/equal (`||=`) won't work directly without specifiyng explicit receiver of course (`self.attr ||=` will work)
32
+ - Also, `self` wouldn't work with `case` operator - I don't want to hack reciever class `.===` just for that.
33
+ Although, you may use `_self` for this (original object).
34
+
35
+ <% %w[closure_binding typing operators aliases collisions].each do |spec| %>
36
+ - <%= spec = "spec/#{spec}_spec.rb";"[#{spec}](#{spec})"%>
37
+ <% end %>
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,42 @@
1
+ require 'forwardable'
2
+ class RedBikini::Bikini
3
+ extend ::Forwardable
4
+
5
+
6
+ def initialize object
7
+ @__in_bikini__ = object
8
+ end
9
+
10
+ def === other
11
+ @__in_bikini__ === other
12
+ end
13
+
14
+ def _self
15
+ @__in_bikini__
16
+ end
17
+
18
+ def object_method method
19
+ original(method) or setter_imitated_by(method)
20
+ end
21
+ def original method
22
+ @__in_bikini__.respond_to?(method, true) and method
23
+ end
24
+
25
+ def respond_to_missing? method, *args
26
+ @__in_bikini__.respond_to?(object_method(method), *args)
27
+ end
28
+ def method_missing method, *args
29
+ @__in_bikini__.public_send(object_method(method), *args)
30
+ end
31
+
32
+
33
+ def setter_imitated_by method
34
+ [/set_(?<attr>\w+)/,/(?<attr>\w+)(_are|_is)/].find do |setter_matcher|
35
+ String(method).match(setter_matcher){|match| return match['attr'] + ?= }
36
+ end
37
+ end
38
+
39
+ def_delegators :@__in_bikini__, :is_a?, :kind_of?, :instance_of?, :class
40
+
41
+
42
+ end
@@ -0,0 +1,3 @@
1
+ module RedBikini
2
+ VERSION = "0.0.1"
3
+ end
data/lib/red_bikini.rb ADDED
@@ -0,0 +1,41 @@
1
+ module RedBikini
2
+ require_relative 'red_bikini/bikini'
3
+
4
+ def self.add_to_wardrobe! klass=Object
5
+ klass.send :include, InstanceMethods
6
+ klass.send :extend, ClassMethods
7
+ end
8
+
9
+ ExecuteInWrappedContext = ->(receiver, args, block) do
10
+ Bikini.new(receiver).instance_exec *args, &block
11
+ end
12
+
13
+ module InstanceMethods
14
+ def in_public *args, &block
15
+ tap{self.expose *args, &block}
16
+ end
17
+ alias in_bikini in_public
18
+ def expose *args, &block
19
+ ExecuteInWrappedContext.call self, args, block
20
+ end
21
+ alias tell expose
22
+ alias confide expose
23
+ end
24
+
25
+
26
+ module ClassMethods
27
+ def such_that *args, &description
28
+ new(*args).in_public &description
29
+ end
30
+ end
31
+
32
+
33
+ ::Kernel.module_exec do
34
+ def which &block
35
+ proc{|receiver|receiver.expose &block}
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+
@@ -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 'red_bikini/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "red_bikini"
8
+ spec.version = RedBikini::VERSION
9
+ spec.authors = ["Andrey Titov"]
10
+ spec.email = ["terracote@gmail.com"]
11
+ spec.description = %q{think of public_exec:}
12
+ spec.summary = %q{ instance_exec run on wrapped receiver, with respect to private methods and setter aliases}
13
+ spec.homepage = "https://github.com/idrozd/red_bikini"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec", "~> 2.14"
24
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ for t in *.erb; do o=$(basename $t .erb); erb $t > $o && git add $o || exit 1; done
3
+ rspec
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ scripts=`dirname $(readlink -nf $0)`
3
+ ln -s $scripts/git_hooks/pre-commit $scripts/../.git/hooks -f
@@ -0,0 +1,23 @@
1
+ describe RedBikini, 'aliases' do
2
+ before {RedBikini.add_to_wardrobe! Person}
3
+
4
+ example do
5
+ patrick = Person.new(1,'Patrick')
6
+
7
+ [
8
+ patrick.expose{"I'm #{name}"},
9
+ patrick.tell{"I'm #{name}"},
10
+ patrick.confide{"I'm #{name}"},
11
+ "I'm Patrick"
12
+ ].uniq.should have(1).string
13
+ end
14
+
15
+
16
+ example '#in_public and #in_bikini are just tap expose' do
17
+ [
18
+ Person.new.in_public{nickname_is 'Dredd'},
19
+ Person.new.in_bikini{set_nickname 'Dredd'},
20
+ Person.new(nil,nil,nil,'Dredd')
21
+ ].uniq.should have(1).element
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ describe RedBikini do
2
+
3
+ before{RedBikini.add_to_wardrobe! Person}
4
+
5
+
6
+ describe 'closure stuff' do
7
+ let(:joe){Person.new(1,'Joe')}
8
+ HOST_CONST = 'Joe is best'
9
+ example{name = 'Local Joe'; expect(joe.tell{name}).to eq 'Local Joe'}
10
+ context 'there is caller method with same name' do
11
+ let(:name){'Host Joe'}
12
+ specify{expect(joe.tell{name}).to eq 'Joe'}
13
+ end
14
+ specify{expect(joe.tell{HOST_CONST}).to eq 'Joe is best'}
15
+ specify{expect(joe.tell{OWN_CONST}).to eq 'Person const'}
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ describe RedBikini, 'name collisions' do
2
+ example do
3
+ Battlecruiser = Class.new do
4
+ attr_accessor :captain_has_parrot, :the_course
5
+ def set_the_course where
6
+ "Course is set! Heading #{where}"
7
+ end
8
+ end
9
+
10
+ RedBikini.add_to_wardrobe! Battlecruiser
11
+
12
+ battlecruiser = Battlecruiser.such_that do
13
+ set_the_course 'nowhere'
14
+ captain_has_parrot_is true
15
+ end
16
+
17
+ battlecruiser.the_course.should be_nil
18
+ battlecruiser.captain_has_parrot.should eq true
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ describe RedBikini do
2
+
3
+ before{RedBikini.add_to_wardrobe! Person}
4
+
5
+
6
+ describe do
7
+ example{expect(Person.new(1,'Jack').in_public{name ||= 'George'}.name).to eq 'Jack'}
8
+ example{expect(Person.new(1,nil).in_public{name ||= 'George'}.name).to eq nil}
9
+ example{expect(Person.new(1,nil).in_public{self.name ||= 'George'}.name).to eq 'George'}
10
+ example{expect(Person.new(1,nil).in_public{name_is name || 'George'}.name).to eq 'George'}
11
+ # ... and so on. You`ve got the point
12
+ end
13
+ end
data/spec/person.rb ADDED
@@ -0,0 +1,14 @@
1
+ Person = Struct.new(:id, :name, :friends, :nickname) do
2
+ OWN_CONST = 'Person const'
3
+ def === other
4
+ other.respond_to? :id and id == other.id
5
+ end
6
+ private
7
+ def credit_card_number
8
+ 'meh'
9
+ end
10
+ protected
11
+ def girly_secrets
12
+ 'nah'
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ describe RedBikini do
2
+
3
+ before{RedBikini.add_to_wardrobe! Person}
4
+
5
+ example 'punchline', contrived: true do
6
+ time = '17:00'
7
+
8
+ expect("Tom, Gia and 'Happy' Mike are heading to the cinema at 17:00").to eq(
9
+ Person.such_that do
10
+ name_is 'Mike'
11
+ friends_are %w[Tom Gia]
12
+ set_nickname 'Happy'
13
+ end.confide('the cinema') do |where|
14
+ "#{friends * ', '} and '#{nickname}' #{name} are heading to #{where} at #{time}"
15
+ end
16
+ )
17
+
18
+ end
19
+
20
+ describe 'access' do
21
+ let(:josephine){ Person.new(1,'Josephine')}
22
+ specify do
23
+ expect{josephine.tell{credit_card_number}}
24
+ .to raise_error NoMethodError # private
25
+ end
26
+ specify do
27
+ expect{josephine.expose{girly_secrets}}
28
+ .to raise_error NoMethodError # protected
29
+ end
30
+ end
31
+
32
+ describe 'Kernel#which' do
33
+ example :even_more_contrived do
34
+ [Person.new(nil, 'George'),
35
+ Person.new(nil, 'Kevin' ),
36
+ Person.new(nil, 'Steven'),
37
+ Person.new(22)].
38
+
39
+ find_all(&which{name and name =~ /ev/}).
40
+
41
+ map(&:name).
42
+ should eq %w[Kevin Steven]
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1 @@
1
+ require_relative '../lib/red_bikini'
@@ -0,0 +1,24 @@
1
+ describe RedBikini do
2
+
3
+ before{RedBikini.add_to_wardrobe! Person}
4
+
5
+ describe 'hacked typing' do
6
+ let(:a_person){Person.new(1,'Joe')}
7
+ specify{expect(a_person.tell{self.is_a? Person}).to be_true}
8
+ specify{expect(a_person.tell{self.instance_of? Person}).to be_true}
9
+ specify{expect(a_person.tell{is_a? Person}).to be_true}
10
+ specify{expect(a_person.tell{instance_of? Person}).to be_true}
11
+ specify{expect(a_person.tell{self.class}).to eq Person}
12
+ specify{expect(a_person.tell{kind_of? Person}).to be_true}
13
+ specify{expect(a_person.tell{self}).to be_a Person}
14
+ specify :gotcha do
15
+ expect(a_person.tell{Person === self}).to be_false
16
+
17
+ expect(a_person.tell{Person === _self}).to be_true
18
+ expect(a_person.tell{Person === @__in_bikini__}).to be_true
19
+ end
20
+ specify{expect(a_person.tell{self === Person}).to be_false} # As expected
21
+ specify{expect(a_person.tell{self === Person.new(1)}).to be_true}
22
+ specify{RedBikini.add_to_wardrobe! Class; expect(Fixnum.tell{self === 1}).to be_true}
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: red_bikini
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrey Titov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.14'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ description: ! 'think of public_exec:'
63
+ email:
64
+ - terracote@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - .travis.yml
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - LICENSE
75
+ - README.md
76
+ - README.md.erb
77
+ - Rakefile
78
+ - lib/red_bikini.rb
79
+ - lib/red_bikini/bikini.rb
80
+ - lib/red_bikini/version.rb
81
+ - red_bikini.gemspec
82
+ - script/git_hooks/pre-commit
83
+ - script/install_git_hooks
84
+ - spec/aliases_spec.rb
85
+ - spec/closure_binding_spec.rb
86
+ - spec/collisions_spec.rb
87
+ - spec/operators_spec.rb
88
+ - spec/person.rb
89
+ - spec/show_off_spec.rb
90
+ - spec/spec_helper.rb
91
+ - spec/typing_spec.rb
92
+ homepage: https://github.com/idrozd/red_bikini
93
+ licenses:
94
+ - MIT
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ segments:
106
+ - 0
107
+ hash: -120012333
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ segments:
115
+ - 0
116
+ hash: -120012333
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 1.8.25
120
+ signing_key:
121
+ specification_version: 3
122
+ summary: instance_exec run on wrapped receiver, with respect to private methods and
123
+ setter aliases
124
+ test_files:
125
+ - spec/aliases_spec.rb
126
+ - spec/closure_binding_spec.rb
127
+ - spec/collisions_spec.rb
128
+ - spec/operators_spec.rb
129
+ - spec/person.rb
130
+ - spec/show_off_spec.rb
131
+ - spec/spec_helper.rb
132
+ - spec/typing_spec.rb