codeodor-with 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +17 -0
- data/README +105 -0
- data/Rakefile +27 -0
- data/lib/with.rb +96 -0
- data/lib/with_on_object.rb +7 -0
- data/lib/with_sexp_processor.rb +33 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/foo.rb +21 -0
- data/test/test_helper.rb +3 -0
- data/test/test_with.rb +103 -0
- data/test/with_on_object_test.rb +101 -0
- data/test/with_test.rb +103 -0
- metadata +93 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
lib/with.rb
|
7
|
+
lib/with_on_object.rb
|
8
|
+
lib/with_sexp_processor.rb
|
9
|
+
script/console
|
10
|
+
script/destroy
|
11
|
+
script/generate
|
12
|
+
test/foo.rb
|
13
|
+
test/test_helper.rb
|
14
|
+
test/test_with.rb
|
15
|
+
test/with_on_object_test.rb
|
16
|
+
test/with_test.rb
|
17
|
+
with.tmproj
|
data/README
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
= with
|
2
|
+
|
3
|
+
* http://github.com/codeodor/with/tree/master
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
I sometimes get a little descriptive with my variable names, so when you're doing a lot of work
|
8
|
+
specifically with one object, it gets especially ugly and repetetive, making the code harder to
|
9
|
+
read than it needs to be:
|
10
|
+
|
11
|
+
@contract_participants_on_drugs.contract_id = params[:contract_id]
|
12
|
+
@contract_participants_on_drugs.participant_name = params[:participant_name]
|
13
|
+
@contract_participants_on_drugs.drug_conviction = DrugConvictions.find(:wtf => 'this is getting ridiculous')
|
14
|
+
...
|
15
|
+
|
16
|
+
And so on. It gets ridiculous.
|
17
|
+
|
18
|
+
Utility Belt implements a with(object) method via a change to Object:
|
19
|
+
|
20
|
+
class Object
|
21
|
+
#utility belt implementation
|
22
|
+
def with(object, &block)
|
23
|
+
object.instance_eval &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Unfortunately, that just executes the block in the context of the object, so there isn't any
|
28
|
+
crossover, nor can you perform assignments with attr_accessors (that I was able to do, anyway).
|
29
|
+
|
30
|
+
So, here's With.object() to fill the void.
|
31
|
+
|
32
|
+
With.object(@foo) do
|
33
|
+
a = "wtf"
|
34
|
+
b = "this is not as bad"
|
35
|
+
end
|
36
|
+
|
37
|
+
In the above example, @foo.a and @foo.b are the variables getting set.
|
38
|
+
|
39
|
+
If you prefer, you can require 'with_on_object' instead and use the notation with(object) do ... end.
|
40
|
+
|
41
|
+
The tests in the /test directory offer more examples of what's been implemented and tested so far
|
42
|
+
(except where noted - namely performing assignment to a variable that was declared outside the
|
43
|
+
block, and is not on @foo).
|
44
|
+
|
45
|
+
Not everything is working yet, but it works for the simplest, most common cases I've run up
|
46
|
+
against. More complex tests are on the way, along with code to make them pass.
|
47
|
+
|
48
|
+
Special thanks to Reg Braithwaite, for help and ideas along the way.
|
49
|
+
|
50
|
+
|
51
|
+
== FEATURES/PROBLEMS:
|
52
|
+
|
53
|
+
The tests in the /test directory offer more examples of what's been implemented and tested so far
|
54
|
+
(except where noted - namely performing assignment to a variable that was declared outside the
|
55
|
+
block, and is not on @foo).
|
56
|
+
|
57
|
+
== SYNOPSIS:
|
58
|
+
|
59
|
+
require 'with'
|
60
|
+
With.object(@foo) do
|
61
|
+
a = "wtf"
|
62
|
+
b = "this is not as bad"
|
63
|
+
end
|
64
|
+
|
65
|
+
or
|
66
|
+
|
67
|
+
require 'with_on_object'
|
68
|
+
with(@foo) do
|
69
|
+
a = "wtf"
|
70
|
+
b = "this is not as bad"
|
71
|
+
end
|
72
|
+
|
73
|
+
== REQUIREMENTS:
|
74
|
+
|
75
|
+
* Ruby2Ruby
|
76
|
+
* ParseTree
|
77
|
+
|
78
|
+
== INSTALL:
|
79
|
+
|
80
|
+
* sudo gem install codeodor-with -s http://gems. github.com
|
81
|
+
|
82
|
+
== LICENSE:
|
83
|
+
|
84
|
+
(The MIT License)
|
85
|
+
|
86
|
+
Copyright (c) 2009 FIX
|
87
|
+
|
88
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
89
|
+
a copy of this software and associated documentation files (the
|
90
|
+
'Software'), to deal in the Software without restriction, including
|
91
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
92
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
93
|
+
permit persons to whom the Software is furnished to do so, subject to
|
94
|
+
the following conditions:
|
95
|
+
|
96
|
+
The above copyright notice and this permission notice shall be
|
97
|
+
included in all copies or substantial portions of the Software.
|
98
|
+
|
99
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
100
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
101
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
102
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
103
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
104
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
105
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/with'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('with', With::VERSION) do |p|
|
7
|
+
p.developer('Sammy Larbi', 'sam@codeodor.com')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.rubyforge_name = p.name # TODO this is default value
|
10
|
+
# p.extra_deps = [
|
11
|
+
# ['activesupport','>= 2.0.2'],
|
12
|
+
# ]
|
13
|
+
p.extra_dev_deps = [
|
14
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
15
|
+
]
|
16
|
+
|
17
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
18
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
19
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
20
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
24
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
25
|
+
|
26
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
27
|
+
# task :default => [:spec, :features]
|
data/lib/with.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'with_sexp_processor'
|
2
|
+
require 'parse_tree'
|
3
|
+
|
4
|
+
class With
|
5
|
+
VERSION = "0.0.1"
|
6
|
+
def self.object(the_object, &block)
|
7
|
+
@the_object = the_object
|
8
|
+
@original_context = block.binding
|
9
|
+
|
10
|
+
anonymous_class = Class.new
|
11
|
+
anonymous_class.instance_eval { define_method("the_block", block) }
|
12
|
+
anonymous_class_as_sexp = ParseTree.translate(anonymous_class)
|
13
|
+
|
14
|
+
our_block_sexp = anonymous_class_as_sexp[3][2][2]
|
15
|
+
our_block_sexp = transform(our_block_sexp)
|
16
|
+
|
17
|
+
transformed_block = lambda { eval(WithSexpProcessor.new.process(our_block_sexp)) } #, block.binding) }
|
18
|
+
transformed_block.call
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def self.convert_single_statement_to_block(node)
|
23
|
+
node = [:block, node] if node[0] != :block
|
24
|
+
return node
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.statements_to_process
|
28
|
+
[:dasgn_curr, :lasgn, :fcall, :vcall]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.transform( node )
|
32
|
+
node = convert_single_statement_to_block node
|
33
|
+
|
34
|
+
node.each_with_index do |statement, i|
|
35
|
+
next if i == 0
|
36
|
+
|
37
|
+
statement_type = statement[0]
|
38
|
+
statement = self.method("transform_#{statement_type.to_s}").call(statement) if statements_to_process.include? statement_type
|
39
|
+
node[i] = statement
|
40
|
+
end
|
41
|
+
|
42
|
+
return node
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.transform_dasgn_curr statement
|
46
|
+
var_name = statement[1].to_s
|
47
|
+
value = statement[2]
|
48
|
+
new_method = (var_name+"=").to_sym
|
49
|
+
|
50
|
+
#binds to original context since we lose original_object name and cannot eval in that context
|
51
|
+
value[1] = eval(value[1].to_s, @original_context) if (value[0]==:lvar || value[0]==:vcall) && !@the_object.respond_to?(value[1].to_s)
|
52
|
+
|
53
|
+
if value[0]==:fcall
|
54
|
+
func = value[1]
|
55
|
+
args = value[2]
|
56
|
+
arg_list = ""
|
57
|
+
args.each_with_index do |arg, j|
|
58
|
+
next if j == 0
|
59
|
+
|
60
|
+
arg[1] = eval(arg[1].to_s, @original_context) if arg[0] != :lit
|
61
|
+
|
62
|
+
arg_list << arg[1].to_s
|
63
|
+
arg_list << "," if j < args.length-1
|
64
|
+
end
|
65
|
+
funcall = "#{func}(#{arg_list})"
|
66
|
+
|
67
|
+
value=[:lit, eval(funcall, @original_context)]
|
68
|
+
end
|
69
|
+
|
70
|
+
statement = [:attrasgn, [:lvar, :the_object], new_method, value]
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.transform_lasgn statement
|
74
|
+
method = statement[2][1]
|
75
|
+
if @the_object.respond_to?(method)
|
76
|
+
lvar = statement[1]
|
77
|
+
statement = [:lasgn, lvar, [:call, [:lvar, :the_object], method]]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.transform_fcall statement
|
82
|
+
method = statement[1]
|
83
|
+
args = statement[2]
|
84
|
+
args.each_with_index do |arg, j|
|
85
|
+
next if j == 0
|
86
|
+
arg[1] = eval(arg[1].to_s, @original_context) if arg[0] == :lvar && !@the_object.respond_to?(arg[1].to_s)
|
87
|
+
end
|
88
|
+
statement = [:call, [:lvar, :the_object], method, args]
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.transform_vcall statement
|
92
|
+
method = statement[1]
|
93
|
+
statement = [:call, [:lvar, :the_object], method]
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby2ruby'
|
3
|
+
|
4
|
+
class WithSexpProcessor < Ruby2Ruby
|
5
|
+
|
6
|
+
def process_vcall(exp)
|
7
|
+
exp.shift.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def process(exp)
|
11
|
+
hacked=true && hack_nil unless nil.respond_to? "empty?"
|
12
|
+
result = super(exp)
|
13
|
+
unhack_nil if hacked
|
14
|
+
return result
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def hack_nil
|
19
|
+
::NilClass.module_eval do
|
20
|
+
def empty?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def unhack_nil
|
27
|
+
::NilClass.module_eval do
|
28
|
+
def empty?
|
29
|
+
throw NoMethodError, "undefined method `empty?' for nil:NilClass"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/with.rb'}"
|
9
|
+
puts "Loading with gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/foo.rb
ADDED
data/test/test_helper.rb
ADDED
data/test/test_with.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'with'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'foo'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class TestWith < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@foo = Foo.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_With_works_with_attr_accessor_assignment
|
14
|
+
foo = Foo.new
|
15
|
+
With.object(foo) do
|
16
|
+
get = 'got!'
|
17
|
+
end
|
18
|
+
assert(foo.get == "got!")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_With_works_with_two_attr_accessor_assignments
|
22
|
+
# Seems strange, but one line blocks don't show up as blocks after running through ParseTree,
|
23
|
+
# so this exercises the more common case, whereas the previous test exercises the uncommon one.
|
24
|
+
With.object(@foo) do
|
25
|
+
get = 'got!'
|
26
|
+
a = 'b'
|
27
|
+
end
|
28
|
+
assert(@foo.get == "got!")
|
29
|
+
assert(@foo.a == "b")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_With_works_with_method_call_no_args
|
33
|
+
With.object(@foo) do
|
34
|
+
get = 'got!'
|
35
|
+
change
|
36
|
+
end
|
37
|
+
assert(@foo.a == "changed!")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_With_works_with_method_call_with_args
|
41
|
+
With.object @foo do
|
42
|
+
set("c", "d")
|
43
|
+
set("d", "e")
|
44
|
+
end
|
45
|
+
assert @foo.a == "d"
|
46
|
+
assert @foo.b == "e"
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_With_ignores_calls_to_methods_where_foo_respond_to?_is_false
|
50
|
+
With.object(@foo) do
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
assert( true )
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_With_works_with_assignment_to_outside_method_call_no_args
|
57
|
+
def outter
|
58
|
+
5
|
59
|
+
end
|
60
|
+
With.object(@foo) do
|
61
|
+
a = outter
|
62
|
+
end
|
63
|
+
|
64
|
+
assert(@foo.a == 5)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_With_works_with_assignment_to_outside_lvar
|
68
|
+
outter = "outside"
|
69
|
+
With.object(@foo) do
|
70
|
+
outter = get
|
71
|
+
end
|
72
|
+
assert( outter == @foo.get )
|
73
|
+
#this fails. unsure how / if it should stay as part of the spec
|
74
|
+
#problem is that (as far as I can tell) it will need to evaluate the post-transformation
|
75
|
+
#block in the original context, whereas it currently needs to be executed in a diff one
|
76
|
+
#this would be a lot easier - less transforms on other specs - if we could find the variable
|
77
|
+
#name of "@foo" within With.object
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_With_works_with_assignment_to_outside_method_call_with_args
|
81
|
+
def f(x,y)
|
82
|
+
398
|
83
|
+
end
|
84
|
+
With.object(@foo) do
|
85
|
+
a = f(1,3)
|
86
|
+
end
|
87
|
+
assert(@foo.a == 398)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_With_works_with_method_call_with_args_using_non_literals
|
91
|
+
def f2(x,y)
|
92
|
+
398
|
93
|
+
end
|
94
|
+
x = 2
|
95
|
+
y = 5
|
96
|
+
With.object(@foo) do
|
97
|
+
a = f2(x,y)
|
98
|
+
end
|
99
|
+
assert(@foo.a == 398)
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require '../lib/with_on_object'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'foo'
|
4
|
+
|
5
|
+
class TestWithOnObject < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@foo = Foo.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_With_works_with_attr_accessor_assignment
|
12
|
+
foo = Foo.new
|
13
|
+
with(foo) do
|
14
|
+
get = 'got!'
|
15
|
+
end
|
16
|
+
assert(foo.get == "got!")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_With_works_with_two_attr_accessor_assignments
|
20
|
+
# Seems strange, but one line blocks don't show up as blocks after running through ParseTree,
|
21
|
+
# so this exercises the more common case, whereas the previous test exercises the uncommon one.
|
22
|
+
with(@foo) do
|
23
|
+
get = 'got!'
|
24
|
+
a = 'b'
|
25
|
+
end
|
26
|
+
assert(@foo.get == "got!")
|
27
|
+
assert(@foo.a == "b")
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_With_works_with_method_call_no_args
|
31
|
+
with(@foo) do
|
32
|
+
get = 'got!'
|
33
|
+
change
|
34
|
+
end
|
35
|
+
assert(@foo.a == "changed!")
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_With_works_with_method_call_with_args
|
39
|
+
With.object @foo do
|
40
|
+
set("c", "d")
|
41
|
+
set("d", "e")
|
42
|
+
end
|
43
|
+
assert @foo.a == "d"
|
44
|
+
assert @foo.b == "e"
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_With_ignores_calls_to_methods_where_foo_respond_to?_is_false
|
48
|
+
with(@foo) do
|
49
|
+
puts
|
50
|
+
end
|
51
|
+
assert( true )
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_With_works_with_assignment_to_outside_method_call_no_args
|
55
|
+
def outter
|
56
|
+
5
|
57
|
+
end
|
58
|
+
with(@foo) do
|
59
|
+
a = outter
|
60
|
+
end
|
61
|
+
|
62
|
+
assert(@foo.a == 5)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_With_works_with_assignment_to_outside_lvar
|
66
|
+
outter = "outside"
|
67
|
+
with(@foo) do
|
68
|
+
outter = get
|
69
|
+
end
|
70
|
+
assert( outter == @foo.get )
|
71
|
+
#this fails. unsure how / if it should stay as part of the spec
|
72
|
+
#problem is that (as far as I can tell) it will need to evaluate the post-transformation
|
73
|
+
#block in the original context, whereas it currently needs to be executed in a diff one
|
74
|
+
#this would be a lot easier - less transforms on other specs - if we could find the variable
|
75
|
+
#name of "@foo" within With.object
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_With_works_with_assignment_to_outside_method_call_with_args
|
79
|
+
def f(x,y)
|
80
|
+
398
|
81
|
+
end
|
82
|
+
with(@foo) do
|
83
|
+
a = f(1,3)
|
84
|
+
end
|
85
|
+
assert(@foo.a == 398)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_With_works_with_method_call_with_args_using_non_literals
|
89
|
+
def f(x,y)
|
90
|
+
398
|
91
|
+
end
|
92
|
+
x = 2
|
93
|
+
y = 5
|
94
|
+
with(@foo) do
|
95
|
+
a = f(x,y)
|
96
|
+
end
|
97
|
+
assert(@foo.a == 398)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
end
|
data/test/with_test.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require '../lib/with'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'foo'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class TestWith < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@foo = Foo.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_With_works_with_attr_accessor_assignment
|
14
|
+
foo = Foo.new
|
15
|
+
With.object(foo) do
|
16
|
+
get = 'got!'
|
17
|
+
end
|
18
|
+
assert(foo.get == "got!")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_With_works_with_two_attr_accessor_assignments
|
22
|
+
# Seems strange, but one line blocks don't show up as blocks after running through ParseTree,
|
23
|
+
# so this exercises the more common case, whereas the previous test exercises the uncommon one.
|
24
|
+
With.object(@foo) do
|
25
|
+
get = 'got!'
|
26
|
+
a = 'b'
|
27
|
+
end
|
28
|
+
assert(@foo.get == "got!")
|
29
|
+
assert(@foo.a == "b")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_With_works_with_method_call_no_args
|
33
|
+
With.object(@foo) do
|
34
|
+
get = 'got!'
|
35
|
+
change
|
36
|
+
end
|
37
|
+
assert(@foo.a == "changed!")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_With_works_with_method_call_with_args
|
41
|
+
With.object @foo do
|
42
|
+
set("c", "d")
|
43
|
+
set("d", "e")
|
44
|
+
end
|
45
|
+
assert @foo.a == "d"
|
46
|
+
assert @foo.b == "e"
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_With_ignores_calls_to_methods_where_foo_respond_to?_is_false
|
50
|
+
With.object(@foo) do
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
assert( true )
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_With_works_with_assignment_to_outside_method_call_no_args
|
57
|
+
def outter
|
58
|
+
5
|
59
|
+
end
|
60
|
+
With.object(@foo) do
|
61
|
+
a = outter
|
62
|
+
end
|
63
|
+
|
64
|
+
assert(@foo.a == 5)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_With_works_with_assignment_to_outside_lvar
|
68
|
+
outter = "outside"
|
69
|
+
With.object(@foo) do
|
70
|
+
outter = get
|
71
|
+
end
|
72
|
+
assert( outter == @foo.get )
|
73
|
+
#this fails. unsure how / if it should stay as part of the spec
|
74
|
+
#problem is that (as far as I can tell) it will need to evaluate the post-transformation
|
75
|
+
#block in the original context, whereas it currently needs to be executed in a diff one
|
76
|
+
#this would be a lot easier - less transforms on other specs - if we could find the variable
|
77
|
+
#name of "@foo" within With.object
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_With_works_with_assignment_to_outside_method_call_with_args
|
81
|
+
def f(x,y)
|
82
|
+
398
|
83
|
+
end
|
84
|
+
With.object(@foo) do
|
85
|
+
a = f(1,3)
|
86
|
+
end
|
87
|
+
assert(@foo.a == 398)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_With_works_with_method_call_with_args_using_non_literals
|
91
|
+
def f(x,y)
|
92
|
+
398
|
93
|
+
end
|
94
|
+
x = 2
|
95
|
+
y = 5
|
96
|
+
With.object(@foo) do
|
97
|
+
a = f(x,y)
|
98
|
+
end
|
99
|
+
assert(@foo.a == 398)
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codeodor-with
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sammy Larbi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-12 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.3
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: hoe
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.8.0
|
32
|
+
version:
|
33
|
+
description: "I sometimes get a little descriptive with my variable names, so when you're doing a lot of work specifically with one object, it gets especially ugly and repetetive, making the code harder to read than it needs to be: @contract_participants_on_drugs.contract_id = params[:contract_id] @contract_participants_on_drugs.participant_name = params[:participant_name] @contract_participants_on_drugs.drug_conviction = DrugConvictions.find(:wtf => 'this is getting ridiculous') ... And so on. It gets ridiculous. Utility Belt implements a with(object) method via a change to Object: class Object #utility belt implementation def with(object, &block) object.instance_eval &block end end Unfortunately, that just executes the block in the context of the object, so there isn't any crossover, nor can you perform assignments with attr_accessors (that I was able to do, anyway). So, here's With.object() to fill the void. With.object(@foo) do a = \"wtf\" b = \"this is not as bad\" end In the above example, @foo.a and @foo.b are the variables getting set. If you prefer, you can require 'with_on_object' instead and use the notation with(object) do ... end. The tests in the /test directory offer more examples of what's been implemented and tested so far (except where noted - namely performing assignment to a variable that was declared outside the block, and is not on @foo). Not everything is working yet, but it works for the simplest, most common cases I've run up against. More complex tests are on the way, along with code to make them pass. Special thanks to Reg Braithwaite, for help and ideas along the way."
|
34
|
+
email:
|
35
|
+
- sam@codeodor.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- History.txt
|
42
|
+
- Manifest.txt
|
43
|
+
- PostInstall.txt
|
44
|
+
- README.rdoc
|
45
|
+
files:
|
46
|
+
- History.txt
|
47
|
+
- Manifest.txt
|
48
|
+
- PostInstall.txt
|
49
|
+
- README
|
50
|
+
- README.rdoc
|
51
|
+
- Rakefile
|
52
|
+
- lib/with.rb
|
53
|
+
- lib/with_on_object.rb
|
54
|
+
- lib/with_sexp_processor.rb
|
55
|
+
- script/console
|
56
|
+
- script/destroy
|
57
|
+
- script/generate
|
58
|
+
- test/foo.rb
|
59
|
+
- test/test_helper.rb
|
60
|
+
- test/test_with.rb
|
61
|
+
- test/with_on_object_test.rb
|
62
|
+
- test/with_test.rb
|
63
|
+
- with.tmproj
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/codeodor/with/tree/master
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --main
|
69
|
+
- README
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project: with
|
87
|
+
rubygems_version: 1.2.0
|
88
|
+
signing_key:
|
89
|
+
specification_version: 2
|
90
|
+
summary: "I sometimes get a little descriptive with my variable names, so when you're doing a lot of work specifically with one object, it gets especially ugly and repetetive, making the code harder to read than it needs to be: @contract_participants_on_drugs.contract_id = params[:contract_id] @contract_participants_on_drugs.participant_name = params[:participant_name] @contract_participants_on_drugs.drug_conviction = DrugConvictions.find(:wtf => 'this is getting ridiculous') .."
|
91
|
+
test_files:
|
92
|
+
- test/test_helper.rb
|
93
|
+
- test/test_with.rb
|