forwarding_dsl 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 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: