charlatan 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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order random
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in proxy_object.gemspec
4
+ gemspec
5
+
6
+ gem 'devtools', git: 'https://github.com/rom-rb/devtools', branch: 'master'
7
+
8
+ # Added by devtools
9
+ eval_gemfile 'Gemfile.devtools'
data/Gemfile.devtools ADDED
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ group :development do
4
+ gem 'rake', '~> 10.1.0'
5
+ gem 'rspec', '~> 2.14.1'
6
+ gem 'yard', '~> 0.8.7'
7
+ end
8
+
9
+ group :yard do
10
+ gem 'kramdown', '~> 1.2.0'
11
+ end
12
+
13
+ group :guard do
14
+ gem 'guard', '~> 1.8.1'
15
+ gem 'guard-bundler', '~> 1.0.0'
16
+ gem 'guard-rspec', '~> 3.0.2'
17
+ gem 'guard-rubocop', '~> 0.2.0'
18
+ gem 'guard-mutant', '~> 0.0.1'
19
+
20
+ # file system change event handling
21
+ gem 'listen', '~> 1.3.0'
22
+ gem 'rb-fchange', '~> 0.0.6', require: false
23
+ gem 'rb-fsevent', '~> 0.9.3', require: false
24
+ gem 'rb-inotify', '~> 0.9.0', require: false
25
+
26
+ # notification handling
27
+ gem 'libnotify', '~> 0.8.0', require: false
28
+ gem 'rb-notifu', '~> 0.0.4', require: false
29
+ gem 'terminal-notifier-guard', '~> 1.5.3', require: false
30
+ end
31
+
32
+ group :metrics do
33
+ gem 'coveralls', '~> 0.6.7'
34
+ gem 'flay', '~> 2.4.0'
35
+ gem 'flog', '~> 4.1.1'
36
+ gem 'reek', '~> 1.3.2'
37
+ gem 'rubocop', '~> 0.12.0'
38
+ gem 'simplecov', '~> 0.7.1'
39
+ gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
40
+
41
+ platforms :ruby_19, :ruby_20 do
42
+ gem 'mutant', git: 'https://github.com/mbj/mutant.git'
43
+ gem 'yard-spellcheck', '~> 0.1.5'
44
+ end
45
+ end
46
+
47
+ group :benchmarks do
48
+ gem 'rbench', '~> 0.2.3'
49
+ end
50
+
51
+ platform :jruby do
52
+ group :jruby do
53
+ gem 'jruby-openssl', '~> 0.8.5'
54
+ end
55
+ end
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ guard :rspec do
2
+ #run all specs if configuration is modified
3
+ watch('Guardfile') { 'spec' }
4
+ watch('Gemfile.lock') { 'spec' }
5
+ watch('spec/spec_helper.rb') { 'spec' }
6
+
7
+ # run all specs if supporting files files are modified
8
+ watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
9
+
10
+ # run unit specs if associated lib code is modified
11
+ watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
12
+ watch(%r{\Alib/(.+)/support/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}/#{m[2]}"] }
13
+ watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
14
+
15
+ # run a spec if it is modified
16
+ watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
17
+
18
+ notification :tmux, :display_message => true
19
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Piotr Solnica
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.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Charlatan
2
+
3
+ Turn any object into a proxy delegating to another object. Like that:
4
+
5
+ ``` ruby
6
+ require 'charlatan'
7
+
8
+ class ArrayProxy
9
+ include Charlatan.new(:array)
10
+ end
11
+
12
+ array_proxy = ArrayProxy.new([])
13
+
14
+ array_proxy << 'Hello'
15
+ array_proxy << 'World'
16
+
17
+ array_proxy.size # => 2
18
+ array_proxy.join(' ') # => 'Hello World'
19
+
20
+ # always wraps responses with the proxy class
21
+ other = array_proxy + ['Oh Hai']
22
+ other.class # => ArrayProxy
23
+ ```
24
+
25
+ ## Why?
26
+
27
+ I dunno, you tell me. I just like it. Which I cannot say about SimpleDelegator.
28
+
29
+ ### TODO: explain why
30
+
31
+ ## Installation
32
+
33
+ Add this line to your application's Gemfile:
34
+
35
+ gem 'charlatan'
36
+
37
+ And then execute:
38
+
39
+ $ bundle
40
+
41
+ Or install it yourself as:
42
+
43
+ $ gem install charlatan
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ # Added by devtools
4
+ require 'devtools'
5
+ Devtools.init_rake_tasks
data/charlatan.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'charlatan/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "charlatan"
8
+ spec.version = Charlatan::VERSION
9
+ spec.authors = ["Piotr Solnica"]
10
+ spec.email = ["piotr.solnica@gmail.com"]
11
+ spec.description = %q{Neat delegation for ruby objects}
12
+ spec.summary = spec.summary
13
+ spec.homepage = "https://github.com/solnic/charlatan"
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
+ end
@@ -0,0 +1,2 @@
1
+ ---
2
+ unit_test_timeout: 0.1
data/config/flay.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ threshold: 0
3
+ total_score: 0
data/config/flog.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 0
data/config/mutant.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ name: charlatan
3
+ namespace: Charlatan
data/config/reek.yml ADDED
@@ -0,0 +1,103 @@
1
+ ---
2
+ Attribute:
3
+ enabled: true
4
+ exclude: []
5
+ BooleanParameter:
6
+ enabled: true
7
+ exclude: []
8
+ ClassVariable:
9
+ enabled: true
10
+ exclude: []
11
+ ControlParameter:
12
+ enabled: true
13
+ exclude: []
14
+ DataClump:
15
+ enabled: true
16
+ exclude: []
17
+ max_copies: 2
18
+ min_clump_size: 2
19
+ DuplicateMethodCall:
20
+ enabled: true
21
+ exclude: []
22
+ max_calls: 1
23
+ allow_calls: []
24
+ FeatureEnvy:
25
+ enabled: true
26
+ exclude: []
27
+ IrresponsibleModule:
28
+ enabled: true
29
+ exclude: []
30
+ LongParameterList:
31
+ enabled: true
32
+ exclude: []
33
+ max_params: 2
34
+ overrides:
35
+ initialize:
36
+ max_params: 3
37
+ LongYieldList:
38
+ enabled: true
39
+ exclude: []
40
+ max_params: 2
41
+ NestedIterators:
42
+ enabled: true
43
+ exclude: []
44
+ max_allowed_nesting: 1
45
+ ignore_iterators: []
46
+ NilCheck:
47
+ enabled: true
48
+ exclude: []
49
+ RepeatedConditional:
50
+ enabled: true
51
+ exclude: []
52
+ max_ifs: 1
53
+ TooManyInstanceVariables:
54
+ enabled: true
55
+ exclude: []
56
+ max_instance_variables: 3
57
+ TooManyMethods:
58
+ enabled: true
59
+ exclude: []
60
+ max_methods: 10
61
+ TooManyStatements:
62
+ enabled: true
63
+ exclude:
64
+ - each
65
+ max_statements: 2
66
+ UncommunicativeMethodName:
67
+ enabled: true
68
+ exclude: []
69
+ reject:
70
+ - !ruby/regexp /^[a-z]$/
71
+ - !ruby/regexp /[0-9]$/
72
+ - !ruby/regexp /[A-Z]/
73
+ accept: []
74
+ UncommunicativeModuleName:
75
+ enabled: true
76
+ exclude: []
77
+ reject:
78
+ - !ruby/regexp /^.$/
79
+ - !ruby/regexp /[0-9]$/
80
+ accept: []
81
+ UncommunicativeParameterName:
82
+ enabled: true
83
+ exclude: []
84
+ reject:
85
+ - !ruby/regexp /^.$/
86
+ - !ruby/regexp /[0-9]$/
87
+ - !ruby/regexp /[A-Z]/
88
+ accept: []
89
+ UncommunicativeVariableName:
90
+ enabled: true
91
+ exclude: []
92
+ reject:
93
+ - !ruby/regexp /^.$/
94
+ - !ruby/regexp /[0-9]$/
95
+ - !ruby/regexp /[A-Z]/
96
+ accept: []
97
+ UnusedParameters:
98
+ enabled: true
99
+ exclude: []
100
+ UtilityFunction:
101
+ enabled: true
102
+ exclude: []
103
+ max_helper_calls: 0
@@ -0,0 +1,58 @@
1
+ AllCops:
2
+ Includes:
3
+ - '**/*.rake'
4
+ - 'Gemfile'
5
+ - 'Gemfile.devtools'
6
+ Excludes:
7
+ - '**/vendor/**'
8
+ - '**/benchmarks/**'
9
+
10
+ # Avoid parameter lists longer than five parameters.
11
+ ParameterLists:
12
+ Max: 3
13
+ CountKeywordArgs: true
14
+
15
+ # Avoid more than `Max` levels of nesting.
16
+ BlockNesting:
17
+ Max: 3
18
+
19
+ # Align with the style guide.
20
+ CollectionMethods:
21
+ PreferredMethods:
22
+ collect: 'map'
23
+ inject: 'reduce'
24
+ find: 'detect'
25
+ find_all: 'select'
26
+
27
+ # Do not force public/protected/private keyword to be indented at the same
28
+ # level as the def keyword. My personal preference is to outdent these keywords
29
+ # because I think when scanning code it makes it easier to identify the
30
+ # sections of code and visually separate them. When the keyword is at the same
31
+ # level I think it sort of blends in with the def keywords and makes it harder
32
+ # to scan the code and see where the sections are.
33
+ AccessControl:
34
+ Enabled: false
35
+
36
+ # Limit line length
37
+ LineLength:
38
+ Max: 79
39
+
40
+ # Disable documentation checking until a class needs to be documented once
41
+ Documentation:
42
+ Enabled: false
43
+
44
+ # Do not favor modifier if/unless usage when you have a single-line body
45
+ IfUnlessModifier:
46
+ Enabled: false
47
+
48
+ # Allow case equality operator (in limited use within the specs)
49
+ CaseEquality:
50
+ Enabled: false
51
+
52
+ # Constants do not always have to use SCREAMING_SNAKE_CASE
53
+ ConstantName:
54
+ Enabled: false
55
+
56
+ # Not all trivial readers/writers can be defined with attr_* methods
57
+ TrivialAccessors:
58
+ Enabled: false
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100
data/lib/charlatan.rb ADDED
@@ -0,0 +1,62 @@
1
+ require "charlatan/version"
2
+
3
+ # Charlatan turns your object into a proxy which will forward all method missing
4
+ # calls to object it's wrapping
5
+ #
6
+ # @example
7
+ #
8
+ # class UserPresenter
9
+ # include Charlatan.new(:user)
10
+ # end
11
+ #
12
+ # user = OpenStruct.new(:name => "Jane")
13
+ # presenter = UserPresenter.new(user)
14
+ #
15
+ # user.name # => "Jane"
16
+ # presenter.user == user # => true
17
+ #
18
+ class Charlatan < Module
19
+ attr_reader :name
20
+
21
+ def initialize(name, options = {})
22
+ attr_reader name
23
+ ivar = "@#{name}"
24
+
25
+ define_method(:initialize) do |*args, &block|
26
+ instance_variable_set(ivar, args.first)
27
+ @__proxy_args = args[1..args.size] || []
28
+ end
29
+
30
+ define_method(:__proxy_target__) do
31
+ instance_variable_get(ivar)
32
+ end
33
+
34
+ define_method(:__proxy_kind__) do
35
+ options[:kind] || __proxy_target__.class
36
+ end
37
+
38
+ include Methods
39
+ end
40
+
41
+ module Methods
42
+ def respond_to_missing?(method_name, include_private)
43
+ __proxy_target__.respond_to?(method_name, include_private)
44
+ end
45
+
46
+ def method_missing(method_name, *args, &block)
47
+ if __proxy_target__.respond_to?(method_name)
48
+ response = __proxy_target__.public_send(method_name, *args, &block)
49
+
50
+ if response.equal?(__proxy_target__)
51
+ self
52
+ elsif response.kind_of?(__proxy_kind__)
53
+ self.class.new(*[response]+@__proxy_args)
54
+ else
55
+ response
56
+ end
57
+ else
58
+ super(method_name, *args, &block)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ class Charlatan < Module
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ # SimpleCov MUST be started before require 'rom-relation'
4
+ #
5
+ if ENV['COVERAGE'] == 'true'
6
+ require 'simplecov'
7
+ require 'coveralls'
8
+
9
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ Coveralls::SimpleCov::Formatter
12
+ ]
13
+
14
+ SimpleCov.start do
15
+ command_name 'spec:unit'
16
+
17
+ add_filter 'config'
18
+ add_filter 'spec'
19
+ end
20
+ end
21
+
22
+ require 'charlatan'
23
+ require 'devtools/spec_helper'
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe Charlatan do
4
+ let(:other) { [1, 2, 3] }
5
+ let(:charlatan) { klass.new(other, 'stuff') }
6
+
7
+ let(:klass) do
8
+ Class.new {
9
+ include Charlatan.new(:other)
10
+
11
+ def initialize(other, extra, &block)
12
+ super(other, extra, &block)
13
+ end
14
+ }
15
+ end
16
+
17
+ it 'adds reader method for target object' do
18
+ expect(charlatan.other).to be(other)
19
+ end
20
+
21
+ it 'forwards method calls to target that returns other objects' do
22
+ expect(charlatan.size).to be(3)
23
+ end
24
+
25
+ it 'forwards method calls to target that returns equal object and returns self' do
26
+ expect(charlatan.concat([])).to equal(charlatan)
27
+ end
28
+
29
+ it 'forwards method calls to target that returns a new instance of itself' do
30
+ expect((charlatan + [4]).other).to eql(klass.new([1, 2, 3, 4], 'stuff').other)
31
+ end
32
+
33
+ it 'forwards method calls with a block' do
34
+ expect(charlatan.map(&:to_s).other).to eql(%w(1 2 3))
35
+ end
36
+
37
+ it 'does not mutate original args from the constructor' do
38
+ 2.times do
39
+ expect((charlatan + [4]).other).to eql(klass.new([1, 2, 3, 4], 'stuff').other)
40
+ end
41
+ end
42
+
43
+ it 'responds to methods defined on the target object' do
44
+ expect(charlatan).to respond_to(:concat)
45
+ end
46
+
47
+ it 'does not respond to private methods defined on the target object' do
48
+ expect(charlatan).not_to respond_to(:Integer)
49
+ end
50
+
51
+ it 'does not respond to unknown method names' do
52
+ expect(charlatan).not_to respond_to(:no_idea_what_you_want)
53
+ end
54
+
55
+ it 'raises no method error when method is not defined' do
56
+ expect { charlatan.not_here}.to raise_error(NoMethodError)
57
+ end
58
+
59
+ it 'forwards multiple levels down to the last target' do
60
+ charlatan1 = Class.new { include Charlatan.new(:arr) }
61
+ charlatan2 = Class.new { include Charlatan.new(:charlatan1) }
62
+ charlatan3 = Class.new { include Charlatan.new(:charlatan2) }
63
+
64
+ object = charlatan3.new(charlatan2.new(charlatan1.new([1, 2, 3])))
65
+
66
+ expect(object.size).to be(3)
67
+ end
68
+
69
+ context 'when target kind is provided' do
70
+ subject(:charlatan) { klass.new(other_class.new) }
71
+
72
+ let(:klass) do
73
+ Class.new { include Charlatan.new(:other, :kind => Enumerable) }
74
+ end
75
+
76
+ let(:other_class) do
77
+ Class.new {
78
+ include Enumerable
79
+
80
+ def to_set
81
+ Set[1, 2]
82
+ end
83
+ }
84
+ end
85
+
86
+ it 'forwards to target and returns charlatan for return value that matches the kind' do
87
+ expect(charlatan.to_set).to be_instance_of(charlatan.class)
88
+ end
89
+ end
90
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: charlatan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Piotr Solnica
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-12 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
+ description: Neat delegation for ruby objects
47
+ email:
48
+ - piotr.solnica@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rspec
55
+ - Gemfile
56
+ - Gemfile.devtools
57
+ - Guardfile
58
+ - LICENSE.txt
59
+ - README.md
60
+ - Rakefile
61
+ - charlatan.gemspec
62
+ - config/devtools.yml
63
+ - config/flay.yml
64
+ - config/flog.yml
65
+ - config/mutant.yml
66
+ - config/reek.yml
67
+ - config/rubocop.yml
68
+ - config/yardstick.yml
69
+ - lib/charlatan.rb
70
+ - lib/charlatan/version.rb
71
+ - spec/spec_helper.rb
72
+ - spec/unit/charlatan_spec.rb
73
+ homepage: https://github.com/solnic/charlatan
74
+ licenses:
75
+ - MIT
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 1.8.23
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: ''
98
+ test_files:
99
+ - spec/spec_helper.rb
100
+ - spec/unit/charlatan_spec.rb
101
+ has_rdoc: