forwarding_dsl 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 56f4ed6636f4c824723c54c6322fbe0d05cc0c77
4
+ data.tar.gz: 46851768bf87d94b96d4fefe26b624c061a4e939
5
+ SHA512:
6
+ metadata.gz: e174af406edd12c441f90f1a8349a07303c9ad384bf4e5f22708ce67c729bd37052fbec15c24db2face489d8b045895f62390ccf8be4828d1fb4ba12e4b6e1b7
7
+ data.tar.gz: cf69df76a986390947eadbf5c791e060e369dcc4ca58deb3f644f8b74d8c30227981468d2c927fdad7e363f0c9ebbdf406ca92180c63b386dd85d6b6ca7b7bcd
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .yardoc
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test, :development do
6
+ gem 'gem-release'
7
+ gem 'rspec'
8
+ gem 'pry'
9
+ gem 'rerun'
10
+ gem 'yard'
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Manuel Morales, Workshare ltd., et al.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # ForwardingDsl
2
+
3
+ ForwardingDsl makes it easy to build user friendly DSLs.
4
+ While `ForwardingDsl.run` will allow you to create a DSL from a regular object,
5
+ `ForwardingDsl::Getsetter` will make easy to declare attributes for it.
6
+ It is inspired by the blog post [instance_eval with access to outside scope](http://djellemah.com/blog/2013/10/09/instance-eval-with-access-to-outside-scope/).
7
+
8
+ Benefits:
9
+
10
+ * Makes it trivial to provide a DSL. Wrap anything with `ForwardingDsl.run()` and you are done.
11
+ * Unlike `instance_eval`, only the public API of your object is reachable from the DSL.
12
+ * Unlike `instance_eval`, methods available outside of the DSL are still available inside.
13
+ * Compatible with the explicit `yield(self)`, no DSL, style.
14
+
15
+
16
+ ## Usage
17
+
18
+ Wrap any object to make a DSL out of it:
19
+
20
+ ```ruby
21
+ require 'forwarding_dsl'
22
+
23
+ App = Struct.new(:host, :port)
24
+ app = App.new("localhost", 80)
25
+
26
+ ForwardingDsl.run app do
27
+ host
28
+ end
29
+ # => "localhost"
30
+ ```
31
+
32
+ Use `ForwardingDsl::Getsetter` to declare attributes that receive values
33
+ on a declarative way:
34
+
35
+ ```ruby
36
+ class MyApp
37
+ include ForwardingDsl::Getsetter
38
+
39
+ getsetter :host, :port
40
+
41
+ def initialize &block
42
+ ForwardingDsl.run(my_object, &block)
43
+ end
44
+ end
45
+
46
+ app = MyApp.new do
47
+ host 'localhost'
48
+ port 80
49
+ end
50
+
51
+ app.host # => 'localhost'
52
+ app.port # => 80
53
+ ```
54
+
55
+ `ForwardingDsl` is also compatible with the classic `yield(self)`.
56
+ The context of the block will remain untouched in that case:
57
+
58
+ ```ruby
59
+ app = MyApp.new do |a|
60
+ a.host 'localhost'
61
+ a.port = 80
62
+ end
63
+ ```
64
+
65
+ Methods available outside of the DSL block are also available inside:
66
+
67
+ ```ruby
68
+ def port_configuration
69
+ configuration[:port]
70
+ end
71
+
72
+ app = MyApp.new do
73
+ port port_configuration
74
+ end
75
+ ```
76
+
77
+ If needed, the yielded object is available explicitly through `this`
78
+ and the outer context through `that`:
79
+
80
+ ```ruby
81
+ def port_configuration
82
+ configuration[:port]
83
+ end
84
+
85
+ app = MyApp.new do
86
+ this.port = that.port_configuration
87
+ end
88
+ ```
89
+
90
+
91
+ ## Contributing
92
+
93
+ Do not forget to run the tests with:
94
+
95
+ ```bash
96
+ rake
97
+ ```
98
+
99
+ And bump the version with any of:
100
+
101
+ ```bash
102
+ $ gem bump --version 1.1.1 # Bump the gem version to the given version number
103
+ $ gem bump --version major # Bump the gem version to the next major level (e.g. 0.0.1 to 1.0.0)
104
+ $ gem bump --version minor # Bump the gem version to the next minor level (e.g. 0.0.1 to 0.1.0)
105
+ $ gem bump --version patch # Bump the gem version to the next patch level (e.g. 0.0.1 to 0.0.2)
106
+ ```
107
+
108
+
109
+ ## License
110
+
111
+ Released under the MIT License.
112
+ See the [LICENSE](LICENSE.txt) file for further details.
113
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+
4
+ require 'rspec/core/rake_task'
5
+ task :default => :spec
6
+ task :test => :spec
7
+ desc 'Run all specs'
8
+ RSpec::Core::RakeTask.new('spec') do |spec|
9
+ spec.rspec_opts = %w{}
10
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ gem_name = "forwarding_dsl" # TODO: Rename this
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require "#{gem_name}/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = gem_name
10
+ spec.version = ForwardingDsl::VERSION
11
+ spec.authors = ["Manuel Morales"]
12
+ spec.email = ['manuelmorales@gmail.com']
13
+ spec.description = File.read('README.md').split("\n").reject{|l| l.length == 0 || l =~ /^[#=]+/ }.first
14
+ spec.summary = spec.description
15
+ spec.homepage = "https://github.com/manuelmorales/#{spec.name.gsub('_','-')}"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,10 @@
1
+ require "forwarding_dsl/version"
2
+
3
+ module ForwardingDsl
4
+ autoload :Dsl, 'forwarding_dsl/dsl'
5
+ autoload :Getsetter, 'forwarding_dsl/getsetter'
6
+
7
+ def self.run *args, &block
8
+ Dsl.run *args, &block
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ module ForwardingDsl
2
+ class Dsl
3
+ attr_accessor :this
4
+ attr_accessor :that
5
+
6
+ def self.run target, &block
7
+ return target unless block_given?
8
+
9
+ case block.arity
10
+ when 0 then
11
+ new(target, block.binding.eval('self')).
12
+ send(:instance_exec, &block)
13
+ when 1 then
14
+ block.call target
15
+ else
16
+ raise ArgumentError.new "Wrong number of arguments. Pass 1 or none."
17
+ end
18
+ end
19
+
20
+ def initialize this, that
21
+ @this = this
22
+ @that = that
23
+ end
24
+
25
+ def method_missing name, *args, &block
26
+ if this.respond_to? name
27
+ this.public_send name, *args, &block
28
+ else
29
+ that.public_send name, *args, &block
30
+ end
31
+ end
32
+
33
+ def respond_to_missing? name, *args
34
+ this.respond_to?(name, *args) ||
35
+ that.respond_to?(name, *args) ||
36
+ super
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module ForwardingDsl
2
+ module Getsetter
3
+ NOT_SET = Object.new
4
+
5
+ def self.included klass
6
+ klass.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def getsetter *names
11
+ names.each do |name|
12
+ define_method name do |value = NOT_SET|
13
+ if value == NOT_SET
14
+ instance_variable_get "@#{name}"
15
+ else
16
+ instance_variable_set "@#{name}", value
17
+ end
18
+ end
19
+
20
+ define_method "#{name}=" do |value|
21
+ instance_variable_set "@#{name}", value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module ForwardingDsl
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,132 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe ForwardingDsl::Dsl do
4
+ let(:target_class) do
5
+ Class.new do
6
+ def a_method
7
+ end
8
+
9
+ private
10
+
11
+ def a_private_emthod
12
+ end
13
+ end
14
+ end
15
+
16
+ let(:target) { target_class.new }
17
+
18
+ let(:an_external_method) { :external_result }
19
+
20
+ describe '.run' do
21
+ subject{ ForwardingDsl::Dsl }
22
+
23
+ describe 'with no args' do
24
+ it 'forwards messages to the target' do
25
+ expect(target).to receive(:a_method).with(42)
26
+
27
+ subject.run target do
28
+ a_method 42
29
+ end
30
+ end
31
+
32
+ it 'responds_to? target methods' do
33
+ subject.run target do
34
+ expect(respond_to?(:a_method)).to be true
35
+ end
36
+ end
37
+
38
+ it 'hides private methods' do
39
+ expect do
40
+ subject.run target do
41
+ a_private_method
42
+ end
43
+ end.to raise_error(NoMethodError)
44
+ end
45
+
46
+ it 'allows calling methods from the outside' do
47
+ expect(target).to receive(:a_method).with :external_result
48
+
49
+ subject.run target do
50
+ a_method an_external_method
51
+ end
52
+ end
53
+
54
+ it 'responds_to? external methods' do
55
+ subject.run target do
56
+ expect(respond_to?(:an_external_method)).to be true
57
+ end
58
+ end
59
+
60
+ it 'allows using this' do
61
+ subject.run target do
62
+ expect(this).to be target
63
+ end
64
+ end
65
+
66
+ it 'allows using that' do
67
+ outer_context = self
68
+
69
+ subject.run target do
70
+ expect(that).to be outer_context
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'with 1 arg' do
76
+ it 'forwards no messages to the target' do
77
+ expect(target).not_to receive(:a_method)
78
+
79
+ expect do
80
+ subject.run target do |t|
81
+ a_method 42
82
+ end
83
+ end.to raise_error(NoMethodError)
84
+ end
85
+
86
+ it 'yields the target' do
87
+ subject.run target do |t|
88
+ expect(t).to be target
89
+ end
90
+ end
91
+
92
+ it 'runs in the outer context' do
93
+ outer_context = self
94
+
95
+ subject.run target do |t|
96
+ expect(self).to be outer_context
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'with more args' do
102
+ it 'raises exception' do
103
+ expect(target).not_to receive(:a_method)
104
+
105
+ expect do
106
+ subject.run target do |t, x|
107
+ end
108
+ end.to raise_error(ArgumentError)
109
+ end
110
+ end
111
+
112
+ describe 'with no block' do
113
+ it 'returns the target' do
114
+ expect(subject.run target).to be target
115
+ end
116
+ end
117
+
118
+ describe 'with a zero arity lambda' do
119
+ it 'works normally' do
120
+ expect(target).to receive(:a_method)
121
+ block = lambda { a_method }
122
+
123
+ subject.run target, &block
124
+ end
125
+ end
126
+
127
+ it 'returns the result of the last line' do
128
+ expect(target).to receive(:a_method).and_return(:something)
129
+ expect(subject.run(target){ a_method }).to be :something
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe ForwardingDsl::Getsetter do
4
+ subject { subject_class.new }
5
+ let(:subject_class) { Class.new { include ForwardingDsl::Getsetter } }
6
+
7
+ describe 'getsetter()' do
8
+ it 'allows setting an attribute passing it as an argument' do
9
+ subject_class.class_eval do
10
+ getsetter :name
11
+ end
12
+
13
+ subject.name 'Test'
14
+ expect(subject.name).to eq 'Test'
15
+ end
16
+
17
+ it 'allows setting an attribute by equality' do
18
+ subject_class.class_eval do
19
+ getsetter :name
20
+ end
21
+
22
+ subject.name = 'Test'
23
+ expect(subject.name).to eq 'Test'
24
+ end
25
+
26
+ it 'allows passing several names' do
27
+ subject_class.class_eval do
28
+ getsetter :name, :surname
29
+ end
30
+
31
+ subject.surname 'Test'
32
+ expect(subject.surname).to eq 'Test'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ForwardingDsl do
4
+ it 'has a version' do
5
+ expect(ForwardingDsl::VERSION).not_to be_nil
6
+ end
7
+
8
+ it 'delegates .run() to Dsl' do
9
+ target = double('target')
10
+ expect(target).to receive(:some_method)
11
+
12
+ ForwardingDsl.run target do
13
+ some_method
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'pry'
4
+
5
+ RSpec.configure do |config|
6
+ config.color = true
7
+ config.tty = true
8
+ config.formatter = :documentation # :documentation, :progress, :html, :textmate
9
+ end
10
+
11
+ $LOAD_PATH.unshift File.expand_path('lib')
12
+ require 'forwarding_dsl'
13
+
14
+ $LOAD_PATH.unshift File.expand_path('spec/support')
15
+
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: forwarding_dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Manuel Morales
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-24 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: ForwardingDsl makes it easy to build user friendly DSLs.
42
+ email:
43
+ - manuelmorales@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - forwarding_dsl-0.0.1.gem
54
+ - forwarding_dsl.gemspec
55
+ - lib/forwarding_dsl.rb
56
+ - lib/forwarding_dsl/dsl.rb
57
+ - lib/forwarding_dsl/getsetter.rb
58
+ - lib/forwarding_dsl/version.rb
59
+ - spec/forwarding_dsl/dsl_spec.rb
60
+ - spec/forwarding_dsl/getsetter_spec.rb
61
+ - spec/forwarding_dsl_spec.rb
62
+ - spec/spec_helper.rb
63
+ homepage: https://github.com/manuelmorales/forwarding-dsl
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.2.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: ForwardingDsl makes it easy to build user friendly DSLs.
87
+ test_files:
88
+ - spec/forwarding_dsl/dsl_spec.rb
89
+ - spec/forwarding_dsl/getsetter_spec.rb
90
+ - spec/forwarding_dsl_spec.rb
91
+ - spec/spec_helper.rb
92
+ has_rdoc: