iron-extensions 1.1.5 → 1.2.0
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 +7 -0
- data/History.txt +7 -0
- data/README.rdoc +11 -50
- data/Version.txt +1 -1
- data/lib/iron/extensions/array.rb +0 -12
- data/lib/iron/extensions/enumerable.rb +4 -0
- data/lib/iron/extensions/fixnum.rb +0 -4
- data/lib/iron/extensions/object.rb +4 -0
- data/lib/iron/extensions/string.rb +1 -1
- data/lib/iron/extensions/symbol.rb +0 -5
- data/spec/extensions/enumerable_spec.rb +7 -0
- data/spec/extensions/object_spec.rb +4 -0
- data/spec/extensions/string_spec.rb +6 -0
- metadata +15 -24
- data/lib/iron/extensions/class.rb +0 -46
- data/lib/iron/extensions/dsl_builder.rb +0 -14
- data/lib/iron/extensions/dsl_proxy.rb +0 -176
- data/spec/extensions/dsl_builder_spec.rb +0 -29
- data/spec/extensions/dsl_proxy_spec.rb +0 -110
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 25e58b7dab82ea9ffef58c5d04ad58ba2d9777c9
|
4
|
+
data.tar.gz: 915e17967decb24e1526328b927f1e562357a01b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 63b0cbb8e2702a7645818e80e26557221b919998152f2dd0a9724672b1fa94f3d8839f64e932b31d1784d162d88e3fa379dcb7648979930339c2d150b035ab6e
|
7
|
+
data.tar.gz: 916089267edf2c7735e357f2a9a0535202f6f50f1e4e0a7a2fcc6f1fc2c3f40cf4d1b5128de8e4d0909228ff3facbbe5fb87b7be19a859f1ac5ad3c4d20db004
|
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 1.2.0 / 2015-01-27
|
2
|
+
|
3
|
+
* BREAKING CHANGE: removed DslProxy/DslBuilder and the dsl_* accessor helpers and moved them into the iron-dsl gem
|
4
|
+
* BREAKING CHANGE: removed deprecated Array#rand and Array#rand! - use #shuffle instead
|
5
|
+
* Improved blank? to work on strings containing only whitespace
|
6
|
+
* Improved documentation & specs a bit
|
7
|
+
|
1
8
|
== 1.1.5 / 2014-03-31
|
2
9
|
|
3
10
|
* Fix bug in Enumerable#convert_to_hash where default values (eg hashes) weren't being duplicated
|
data/README.rdoc
CHANGED
@@ -4,7 +4,9 @@ Written by Rob Morris @ Irongaze Consulting LLC (http://irongaze.com)
|
|
4
4
|
|
5
5
|
== DESCRIPTION
|
6
6
|
|
7
|
-
Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
7
|
+
Helpful extensions to core Ruby classes, plus a little sugar for common patterns. For users of
|
8
|
+
version 1.1.x and lower, please note that as of version 1.2.0 the DSL-specific extensions
|
9
|
+
have been moved to the iron-dsl gem!
|
8
10
|
|
9
11
|
== ADDED EXTENSIONS
|
10
12
|
|
@@ -12,48 +14,23 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
12
14
|
|
13
15
|
[1, 2, nil, '', 'count'].list_join # => '1, 2, count'
|
14
16
|
|
15
|
-
*
|
17
|
+
* Enumerable#convert_to_hash - convert an array or other enumerable to a hash using a block or constant
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
builder = MyBuilder.new
|
21
|
-
builder.name 'ProjectX'
|
22
|
-
builder.name # => 'ProjectX'
|
23
|
-
DslProxy.exec(builder) do
|
24
|
-
name 'Project Omega'
|
25
|
-
end
|
26
|
-
builder.name # => 'Project Omega'
|
27
|
-
|
28
|
-
* Class#dsl_flag - same as above, but designed for boolean values
|
29
|
-
|
30
|
-
class AnotherBuilder
|
31
|
-
dsl_flag :awesome
|
32
|
-
end
|
33
|
-
|
34
|
-
builder = AnotherBuilder
|
35
|
-
builder.awesome? # => false on uninitialized value
|
36
|
-
builder.awesome! # => sets @awesome to true
|
37
|
-
builder.awesome true # ditto, same style as dsl_accessor above
|
38
|
-
|
39
|
-
* Enumerable#to_hash - convert an array or other enumerable to a hash using a block or constant
|
40
|
-
|
41
|
-
[:frog, :pig].to_hash {|n| n.to_s.capitalize} # => {:frog => 'Frog', :pig => 'Pig'}
|
42
|
-
[:frog, :pig].to_hash(nil) # => {:frog => nil, :pig => nil}
|
19
|
+
[:frog, :pig].convert_to_hash {|n| n.to_s.capitalize} # => {:frog => 'Frog', :pig => 'Pig'}
|
20
|
+
[:frog, :pig].convert_to_hash(nil) # => {:frog => nil, :pig => nil}
|
43
21
|
|
44
22
|
* Enumerable#delete_unless - equivalent to delete_if but with inverted test
|
45
23
|
|
46
24
|
[1,2,3,4,5].delete_unless(&:odd?) # => [1,3,5]
|
47
25
|
|
48
|
-
* File.
|
26
|
+
* File.safe_replace - atomic replacement of a file given a block to generate it
|
49
27
|
|
50
28
|
# Defers deleting old file until block completes successfully (ie no exceptions), then
|
51
29
|
# moves the new file into the old file's location
|
52
|
-
File.
|
30
|
+
File.safe_replace('./config') do |file|
|
53
31
|
file.write("PRODUCTION: true")
|
54
32
|
end
|
55
33
|
|
56
|
-
* Fixnum#blank? - always false
|
57
34
|
* Fixnum#to_human_size - size to MB/GB/whatever, adapted from Rails
|
58
35
|
|
59
36
|
123456.to_human_size # => "120.5 KB"
|
@@ -75,7 +52,7 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
75
52
|
|
76
53
|
* Nil#blank? - always true
|
77
54
|
|
78
|
-
* Numeric#to_display - pretty display of numbers with options for number of decimal places and inclusion of thousands separator
|
55
|
+
* Numeric#to_display - pretty display of numbers with options for number of decimal places and inclusion of thousands separator (US-only, sorry!)
|
79
56
|
|
80
57
|
5000.to_display # => 5,000
|
81
58
|
100.to_display(2) # => 100.00
|
@@ -97,8 +74,8 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
97
74
|
* Regexp::IP_ADDRESS, Regexp::EMAIL_ADDRESS, Regexp::DOMAIN - commonly useful regexen
|
98
75
|
|
99
76
|
* String#blank? - true if empty?
|
100
|
-
* String#append / String#prepend -
|
101
|
-
* String#to_date - "better" date parser than Date.parse
|
77
|
+
* String#append / String#prepend - these should be in Ruby core
|
78
|
+
* String#to_date - "better" date parser than Date.parse (US-centric)
|
102
79
|
* String#to_dashcase - perfect for permalinks!
|
103
80
|
* String#smart_truncate - truncate honoring word boundaries
|
104
81
|
* String#integer? - true when string represents an integer
|
@@ -110,22 +87,6 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
110
87
|
* Symbol#blank? - always false
|
111
88
|
* Symbol#to_dashcase - same as for String
|
112
89
|
|
113
|
-
== ADDED CLASSES/MODULES
|
114
|
-
|
115
|
-
* DslProxy - a cool and sexy way to make powerful DSLs (domain-specific languages) look easy - see the docs for details
|
116
|
-
|
117
|
-
# DslProxy makes this code possible:
|
118
|
-
@items = ['one', 'two']
|
119
|
-
Console.out do
|
120
|
-
# No explicit receiver for DSL method calls
|
121
|
-
p 'Item List'
|
122
|
-
hr
|
123
|
-
indent do
|
124
|
-
# Even nested, local variables are still available
|
125
|
-
@items.each {|item| p item }
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
90
|
== SYNOPSIS
|
130
91
|
|
131
92
|
To use:
|
data/Version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
@@ -1,17 +1,5 @@
|
|
1
1
|
class Array
|
2
2
|
|
3
|
-
# DEPRECATED: as of Ruby 1.9, you should use Array#sample instead
|
4
|
-
def rand(count = 1)
|
5
|
-
warn("[DEPRECATION] Array#rand is deprecated - use Array#sample instead")
|
6
|
-
shuffle[0...count]
|
7
|
-
end
|
8
|
-
|
9
|
-
# DEPRECATED: as of Ruby 1.9, you should use Array#sample instead
|
10
|
-
def rand!(count = 1)
|
11
|
-
warn("[DEPRECATION] Array#rand is deprecated - use Array#sample instead")
|
12
|
-
self.replace rand(count)
|
13
|
-
end
|
14
|
-
|
15
3
|
# Join an array's values ignoring blank entries
|
16
4
|
def list_join(sep = ', ')
|
17
5
|
self.select{|e| !e.blank?}.join(sep)
|
@@ -78,5 +78,11 @@ describe String do
|
|
78
78
|
it 'should support natural ordering' do
|
79
79
|
['a0', 'a90', 'a10', 'a9'].sort_by {|a| a.natural_order}.should == ['a0', 'a9', 'a10', 'a90']
|
80
80
|
end
|
81
|
+
|
82
|
+
it 'should be appropriately blank' do
|
83
|
+
[nil, '', ' ', "\t", "\n"].each do |test|
|
84
|
+
test.should be_blank
|
85
|
+
end
|
86
|
+
end
|
81
87
|
|
82
88
|
end
|
metadata
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iron-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Rob Morris
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-01-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '2.6'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '2.6'
|
30
27
|
description: Adds common extensions to core Ruby classes
|
@@ -34,10 +31,13 @@ executables: []
|
|
34
31
|
extensions: []
|
35
32
|
extra_rdoc_files: []
|
36
33
|
files:
|
34
|
+
- ".rspec"
|
35
|
+
- History.txt
|
36
|
+
- LICENSE
|
37
|
+
- README.rdoc
|
38
|
+
- Version.txt
|
39
|
+
- lib/iron/extensions.rb
|
37
40
|
- lib/iron/extensions/array.rb
|
38
|
-
- lib/iron/extensions/class.rb
|
39
|
-
- lib/iron/extensions/dsl_builder.rb
|
40
|
-
- lib/iron/extensions/dsl_proxy.rb
|
41
41
|
- lib/iron/extensions/enumerable.rb
|
42
42
|
- lib/iron/extensions/file.rb
|
43
43
|
- lib/iron/extensions/fixnum.rb
|
@@ -50,10 +50,7 @@ files:
|
|
50
50
|
- lib/iron/extensions/regexp.rb
|
51
51
|
- lib/iron/extensions/string.rb
|
52
52
|
- lib/iron/extensions/symbol.rb
|
53
|
-
- lib/iron/extensions.rb
|
54
53
|
- spec/extensions/array_spec.rb
|
55
|
-
- spec/extensions/dsl_builder_spec.rb
|
56
|
-
- spec/extensions/dsl_proxy_spec.rb
|
57
54
|
- spec/extensions/enumerable_spec.rb
|
58
55
|
- spec/extensions/kernel_spec.rb
|
59
56
|
- spec/extensions/numeric_spec.rb
|
@@ -61,34 +58,28 @@ files:
|
|
61
58
|
- spec/extensions/string_spec.rb
|
62
59
|
- spec/extensions/symbol_spec.rb
|
63
60
|
- spec/spec_helper.rb
|
64
|
-
- LICENSE
|
65
|
-
- History.txt
|
66
|
-
- Version.txt
|
67
|
-
- README.rdoc
|
68
|
-
- .rspec
|
69
61
|
homepage: https://github.com/irongaze/iron-extensions
|
70
62
|
licenses:
|
71
63
|
- MIT
|
64
|
+
metadata: {}
|
72
65
|
post_install_message:
|
73
66
|
rdoc_options: []
|
74
67
|
require_paths:
|
75
68
|
- lib
|
76
69
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
-
none: false
|
78
70
|
requirements:
|
79
|
-
- -
|
71
|
+
- - ">="
|
80
72
|
- !ruby/object:Gem::Version
|
81
73
|
version: 1.9.2
|
82
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
75
|
requirements:
|
85
|
-
- -
|
76
|
+
- - ">="
|
86
77
|
- !ruby/object:Gem::Version
|
87
78
|
version: '0'
|
88
79
|
requirements: []
|
89
80
|
rubyforge_project:
|
90
|
-
rubygems_version:
|
81
|
+
rubygems_version: 2.4.3
|
91
82
|
signing_key:
|
92
|
-
specification_version:
|
83
|
+
specification_version: 4
|
93
84
|
summary: Extensions to core classes
|
94
85
|
test_files: []
|
@@ -1,46 +0,0 @@
|
|
1
|
-
class Class
|
2
|
-
|
3
|
-
# Provides a DSL-friendly way to set values. Similar to attr_accessor, but
|
4
|
-
# supports setting values like so:
|
5
|
-
#
|
6
|
-
# class Widget
|
7
|
-
# dsl_accessor :size
|
8
|
-
# end
|
9
|
-
# @w = Widget.new
|
10
|
-
# @w.size = 5 # normal setter, same as...
|
11
|
-
# @w.size 5 # note the lack of explicit = sign
|
12
|
-
# puts @w.size # still get reader access
|
13
|
-
#
|
14
|
-
# Useful in DslProxy blocks:
|
15
|
-
#
|
16
|
-
# DslProxy.exec(Widget.new) do
|
17
|
-
# size 10 # sets size to 10, as expected
|
18
|
-
# size = 10 # fails, creates local variable 'size' instead of invoking Widget#size
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
def dsl_accessor(*keys)
|
22
|
-
keys.each do |key|
|
23
|
-
class_eval "def #{key}(val = :__UNDEFINED); @#{key} = val unless val == :__UNDEFINED; @#{key}; end"
|
24
|
-
class_eval "def #{key}=(val); @#{key} = val; end"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Like #dsl_accessor, but adds imperative and query versions of the keys as well to set the
|
29
|
-
# flag to true and to query the true-ness of the flag.
|
30
|
-
#
|
31
|
-
# class Widget
|
32
|
-
# dsl_flag :heavy
|
33
|
-
# end
|
34
|
-
# @w = Widget.new
|
35
|
-
# @w.heavy? # => false
|
36
|
-
# @w.heavy! # now is true
|
37
|
-
#
|
38
|
-
def dsl_flag(*keys)
|
39
|
-
dsl_accessor(*keys)
|
40
|
-
keys.each do |key|
|
41
|
-
class_eval "def #{key}!; @#{key} = true; end"
|
42
|
-
class_eval "def #{key}?; @#{key} === true; end"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# Provides a base class for building DSL (domain specific language) builder
|
2
|
-
# classes, ie classes that define a minimal subset of methods and act as aggregators
|
3
|
-
# of settings or functionality. Similar to BasicObject in the standard library, but
|
4
|
-
# has methods such as respond_to? and send that are required for any real DSL building
|
5
|
-
# effort.
|
6
|
-
class DslBuilder < Object
|
7
|
-
|
8
|
-
# Remove all methods not explicitly desired
|
9
|
-
instance_methods.each do |m|
|
10
|
-
keepers = [:inspect, :send]
|
11
|
-
undef_method m if m =~ /^[a-z]+[0-9]?$/ && !keepers.include?(m)
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
@@ -1,176 +0,0 @@
|
|
1
|
-
# Specialty helper class for building elegant DSLs (domain-specific languages)
|
2
|
-
# The purpose of the class is to allow seamless DSL's by allowing execution
|
3
|
-
# of blocks with the instance variables of the calling context preserved, but
|
4
|
-
# all method calls proxied to a given receiver. This sounds pretty abstract,
|
5
|
-
# so here's an example:
|
6
|
-
#
|
7
|
-
# class ControlBuilder
|
8
|
-
# def initialize; @controls = []; end
|
9
|
-
# def control_list; @controls; end
|
10
|
-
# def knob; @controls << :knob; end
|
11
|
-
# def button; @controls << :button; end
|
12
|
-
# def switch; @controls << :switch; end
|
13
|
-
# def self.define(&block)
|
14
|
-
# @builder = self.new
|
15
|
-
# DslProxy.exec(@builder, &block)
|
16
|
-
# # Do something here with the builder's list of controls
|
17
|
-
# @builder.control_list
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# @knob_count = 5
|
22
|
-
# new_list = ControlBuilder.define do
|
23
|
-
# switch
|
24
|
-
# @knob_count.times { knob }
|
25
|
-
# button
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# Notice the lack of explicit builder receiver to the calls to #switch, #knob and #button.
|
29
|
-
# Those calls are automatically proxied to the receiver we passed to the DslProxy.
|
30
|
-
#
|
31
|
-
# In quick and dirty DSLs, like Rails' migrations, you end up with a lot of
|
32
|
-
# pointless receiver declarations for each method call, like so:
|
33
|
-
#
|
34
|
-
# def change
|
35
|
-
# create_table do |t|
|
36
|
-
# t.integer :counter
|
37
|
-
# t.text :title
|
38
|
-
# t.text :desc
|
39
|
-
# # ... tired of typing "t." yet? ...
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# This is not a big deal if you're using a simple DSL, but when you have multiple nested
|
44
|
-
# builders going on at once, it is ugly, pointless, and can cause bugs when
|
45
|
-
# the throwaway arg names you choose (eg 't' above) overlap in scope.
|
46
|
-
#
|
47
|
-
# In addition, simply using a yield statment loses the instance variables set in the calling
|
48
|
-
# context. This is a major pain in eg Rails views, where most of the interesting
|
49
|
-
# data resides in instance variables. You can get around this when #yield-ing by
|
50
|
-
# explicitly creating a local variable to be picked up by the closure created in the
|
51
|
-
# block, but it kind of sucks.
|
52
|
-
#
|
53
|
-
# In summary, DslProxy allows you to keep all the local and instance variable context
|
54
|
-
# from your block declarations, while proxying all method calls to a given
|
55
|
-
# receiver. If you're not building DSLs, this class is not for you, but if you are,
|
56
|
-
# I hope it helps!
|
57
|
-
class DslProxy < BasicObject
|
58
|
-
|
59
|
-
# Pass in a builder-style class, or other receiver you want set as "self" within the
|
60
|
-
# block, and off you go. The passed block will be executed with all
|
61
|
-
# block-context local and instance variables available, but with all
|
62
|
-
# method calls sent to the receiver you pass in. The block's result will
|
63
|
-
# be returned.
|
64
|
-
#
|
65
|
-
# If the receiver doesn't respond_to? a method, any missing methods
|
66
|
-
# will be proxied to the enclosing context.
|
67
|
-
def self.exec(receiver, *to_yield, &block) # :yields: receiver
|
68
|
-
# Find the context within which the block was defined
|
69
|
-
context = ::Kernel.eval('self', block.binding)
|
70
|
-
|
71
|
-
# Create or re-use our proxy object
|
72
|
-
if context.respond_to?(:_to_dsl_proxy)
|
73
|
-
# If we're nested, we don't want/need a new dsl proxy, just re-use the existing one
|
74
|
-
proxy = context._to_dsl_proxy
|
75
|
-
else
|
76
|
-
# Not nested, create a new proxy for our use
|
77
|
-
proxy = DslProxy.new(context)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Exec the block and return the result
|
81
|
-
proxy._proxy(receiver, *to_yield, &block)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Simple state setup
|
85
|
-
def initialize(context)
|
86
|
-
@_receivers = []
|
87
|
-
@_instance_original_values = {}
|
88
|
-
@_context = context
|
89
|
-
end
|
90
|
-
|
91
|
-
def _proxy(receiver, *to_yield, &block) # :yields: receiver
|
92
|
-
# Sanity!
|
93
|
-
raise 'Cannot proxy with a DslProxy as receiver!' if receiver.respond_to?(:_to_dsl_proxy)
|
94
|
-
|
95
|
-
if @_receivers.empty?
|
96
|
-
# On first proxy call, run each context instance variable,
|
97
|
-
# and set it to ourselves so we can proxy it
|
98
|
-
@_context.instance_variables.each do |var|
|
99
|
-
unless var.starts_with?('@_')
|
100
|
-
value = @_context.instance_variable_get(var.to_s)
|
101
|
-
@_instance_original_values[var] = value
|
102
|
-
instance_eval "#{var} = value"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# Save the dsl target as our receiver for proxying
|
108
|
-
_push_receiver(receiver)
|
109
|
-
|
110
|
-
# Run the block with ourselves as the new "self", passing the given yieldable(s) or
|
111
|
-
# the receiver in case the code wants to disambiguate for some reason
|
112
|
-
to_yield = [receiver] if to_yield.empty?
|
113
|
-
to_yield = to_yield.first(block.arity)
|
114
|
-
result = instance_exec(*to_yield, &block)
|
115
|
-
|
116
|
-
# Pop the last receiver off the stack
|
117
|
-
_pop_receiver
|
118
|
-
|
119
|
-
if @_receivers.empty?
|
120
|
-
# Run each local instance variable and re-set it back to the context if it has changed during execution
|
121
|
-
#instance_variables.each do |var|
|
122
|
-
@_context.instance_variables.each do |var|
|
123
|
-
unless var.starts_with?('@_')
|
124
|
-
value = instance_eval("#{var}")
|
125
|
-
if @_instance_original_values[var] != value
|
126
|
-
@_context.instance_variable_set(var.to_s, value)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
return result
|
133
|
-
end
|
134
|
-
|
135
|
-
# For nesting multiple proxies
|
136
|
-
def _to_dsl_proxy
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
|
-
# Set the currently active receiver
|
141
|
-
def _push_receiver(receiver)
|
142
|
-
@_receivers.push receiver
|
143
|
-
end
|
144
|
-
|
145
|
-
# Remove the currently active receiver, restore old receiver if nested
|
146
|
-
def _pop_receiver
|
147
|
-
@_receivers.pop
|
148
|
-
end
|
149
|
-
|
150
|
-
# Proxies all calls to our receiver, or to the block's context
|
151
|
-
# if the receiver doesn't respond_to? it.
|
152
|
-
def method_missing(method, *args, &block)
|
153
|
-
#$stderr.puts "Method missing: #{method}"
|
154
|
-
if @_receivers.last.respond_to?(method)
|
155
|
-
#$stderr.puts "Proxy [#{method}] to receiver"
|
156
|
-
@_receivers.last.__send__(method, *args, &block)
|
157
|
-
else
|
158
|
-
#$stderr.puts "Proxy [#{method}] to context"
|
159
|
-
@_context.__send__(method, *args, &block)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Let anyone who's interested know what our proxied objects will accept
|
164
|
-
def respond_to?(method, include_private = false)
|
165
|
-
return true if method == :_to_dsl_proxy
|
166
|
-
@_receivers.last.respond_to?(method, include_private) || @_context.respond_to?(method, include_private)
|
167
|
-
end
|
168
|
-
|
169
|
-
# Proxies searching for constants to the context, so that eg Kernel::foo can actually
|
170
|
-
# find Kernel - BasicObject does not partake in the global scope!
|
171
|
-
def self.const_missing(name)
|
172
|
-
#$stderr.puts "Constant missing: #{name} - proxy to context"
|
173
|
-
@_context.class.const_get(name)
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
describe DslBuilder do
|
2
|
-
|
3
|
-
# TODO: break this out a bit...
|
4
|
-
it 'should allow using DSL-style accessors' do
|
5
|
-
class MyBuilder < DslBuilder
|
6
|
-
dsl_accessor :name
|
7
|
-
dsl_flag :flagged
|
8
|
-
end
|
9
|
-
builder = MyBuilder.new
|
10
|
-
|
11
|
-
# Test standalone
|
12
|
-
builder.name 'ProjectX'
|
13
|
-
builder.name.should == 'ProjectX'
|
14
|
-
|
15
|
-
builder.flagged?.should be_false
|
16
|
-
builder.flagged = true
|
17
|
-
builder.flagged?.should be_true
|
18
|
-
builder.flagged = false
|
19
|
-
|
20
|
-
# Test as part of DslProxy usage (common case)
|
21
|
-
DslProxy.exec(builder) do
|
22
|
-
name 'Project Omega'
|
23
|
-
flagged!
|
24
|
-
end
|
25
|
-
builder.name.should == 'Project Omega'
|
26
|
-
builder.flagged?.should be_true
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
describe DslProxy do
|
2
|
-
|
3
|
-
# Sample DSL builder class for use in testing
|
4
|
-
class ControlBuilder
|
5
|
-
def initialize; @controls = []; end
|
6
|
-
def controls; @controls; end
|
7
|
-
def knob; @controls << :knob; end
|
8
|
-
def button; @controls << :button; end
|
9
|
-
def switch; @controls << :switch; end
|
10
|
-
|
11
|
-
def self.define(&block)
|
12
|
-
@builder = self.new
|
13
|
-
DslProxy.exec(@builder, &block)
|
14
|
-
@builder.controls
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should proxy calls to the receiver' do
|
19
|
-
receiver = Object.new
|
20
|
-
DslProxy.exec(receiver) do
|
21
|
-
self.class.name.should == 'Object'
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should proxy respond_to? to the receiver' do
|
26
|
-
receiver = ControlBuilder.new
|
27
|
-
DslProxy.exec(receiver) do
|
28
|
-
respond_to?(:garbaz).should == false
|
29
|
-
respond_to?(:button).should == true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should proxy local variables from the binding context' do
|
34
|
-
@foo = 'bar'
|
35
|
-
DslProxy.exec(Object.new) do
|
36
|
-
@foo.should == 'bar'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should propagate local variable changes back to the binding context' do
|
41
|
-
@foo = 'bar'
|
42
|
-
DslProxy.exec(Object.new) do
|
43
|
-
@foo = 'no bar!'
|
44
|
-
end
|
45
|
-
@foo.should == 'no bar!'
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'should proxy missing methods on the receiver to the calling context' do
|
49
|
-
class TestContext
|
50
|
-
def bar
|
51
|
-
'something'
|
52
|
-
end
|
53
|
-
|
54
|
-
def test
|
55
|
-
DslProxy.exec(Object.new) do
|
56
|
-
bar
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
TestContext.new.test.should == 'something'
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'should return the result of the block' do
|
65
|
-
res = DslProxy.exec(Object.new) do
|
66
|
-
'foo'
|
67
|
-
end
|
68
|
-
res.should == 'foo'
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should allow access to global constants' do
|
72
|
-
DslProxy.exec(self) do # Use self here, so #be_a is defined. :-)
|
73
|
-
Object.new.should be_a(Object)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'should proxy correctly even when nested' do
|
78
|
-
def outerfunc
|
79
|
-
5
|
80
|
-
end
|
81
|
-
@instance_var = nil
|
82
|
-
local_var = nil
|
83
|
-
DslProxy.exec(self) do
|
84
|
-
DslProxy.exec(Object.new) do
|
85
|
-
outerfunc.should == 5
|
86
|
-
@instance_var.should be_nil
|
87
|
-
local_var.should be_nil
|
88
|
-
@instance_var = 10
|
89
|
-
local_var = 11
|
90
|
-
end
|
91
|
-
end
|
92
|
-
@instance_var.should == 10
|
93
|
-
local_var.should == 11
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'should pass additional args to block as argument' do
|
97
|
-
l = lambda {|arg1, arg2| arg1 + arg2}
|
98
|
-
DslProxy.exec(Object.new, 5, 1, &l).should == 6
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'should put it all together' do
|
102
|
-
@knob_count = 5
|
103
|
-
controls = ControlBuilder.define do
|
104
|
-
switch
|
105
|
-
@knob_count.times { knob }
|
106
|
-
end
|
107
|
-
controls.count.should == 6
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|