dolzenko 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/dolzenko.gemspec +0 -0
- data/lib/dolzenko/django_f_object.rb +213 -0
- data/lib/dolzenko/django_q_object.rb +176 -0
- data/lib/dolzenko/error_print.rb +169 -0
- data/lib/dolzenko/gist_readme.rb +20 -0
- data/lib/dolzenko/includable_with_options.rb +106 -0
- data/lib/dolzenko/io_interceptor.rb +64 -0
- data/lib/dolzenko/remote_download.rb +90 -0
- data/lib/dolzenko/shell_out.rb +386 -0
- data/lib/dolzenko/try_block.rb +189 -0
- data/lib/dolzenko-light.rb +11 -0
- data/lib/dolzenko.rb +1 -11
- metadata +13 -3
data/dolzenko.gemspec
CHANGED
File without changes
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# Django F object for Rails 3
|
2
|
+
# http://docs.djangoproject.com/en/dev/topics/db/queries/#query-expressions
|
3
|
+
#
|
4
|
+
# Let's you reference columns (and do simple calculations on them)
|
5
|
+
# from conditions and updates.
|
6
|
+
#
|
7
|
+
# User.where(:updated_at => F(:created_at))
|
8
|
+
#
|
9
|
+
# instead of User.where("updated_at = created_at")
|
10
|
+
#
|
11
|
+
# User.where(:updated_at => F(:created_at) + 1)
|
12
|
+
#
|
13
|
+
# instead of User.where("updated_at = created_at + 1")
|
14
|
+
#
|
15
|
+
# User.where(:updated_at => F(:created_at) + F(:updated_at))
|
16
|
+
#
|
17
|
+
# instead of User.where("updated_at = created_at + updated_at")
|
18
|
+
#
|
19
|
+
# User.update_all(:mirror_id => F(:id))
|
20
|
+
#
|
21
|
+
# instead of User.update_all("mirror_id = id")
|
22
|
+
#
|
23
|
+
# user = User.find(1)
|
24
|
+
# user.mirror_id = F(:id) + 1
|
25
|
+
# user.save
|
26
|
+
#
|
27
|
+
# issues UPDATE `users` SET `mirror_id` = `users`.`id` + 1 WHERE (`users`.`id` = 1)
|
28
|
+
#
|
29
|
+
#
|
30
|
+
|
31
|
+
require "require_gist"; require_gist "383954/ea5a41269aac073b596b21fe392098827186a32b/alias_method_chain_once.rb", "a6f068593bb45fe6c9956205f672ac4a0c2e1671" # http://gist.github.com/383954
|
32
|
+
|
33
|
+
class F
|
34
|
+
attr_accessor :attr_name
|
35
|
+
attr_accessor :klass
|
36
|
+
attr_accessor :operator
|
37
|
+
attr_accessor :operand
|
38
|
+
|
39
|
+
def initialize(attr_name)
|
40
|
+
self.attr_name = attr_name.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_sql(formatter = nil)
|
44
|
+
self.klass ||= formatter.environment.relation.klass
|
45
|
+
sql = klass.my_quote_columns(attr_name)
|
46
|
+
if operator && operand
|
47
|
+
operand.klass = klass if operand.is_a?(F)
|
48
|
+
sql << " #{ operator } #{ operand.is_a?(F) ? operand.to_sql(formatter) : klass.connection.quote(operand) }"
|
49
|
+
end
|
50
|
+
sql
|
51
|
+
end
|
52
|
+
|
53
|
+
def empty?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
%w(+ - * /).each do |op|
|
58
|
+
define_method(op) do |arg|
|
59
|
+
self.operator = op
|
60
|
+
self.operand = arg
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def F(attr_name)
|
67
|
+
F.new(attr_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
if $PROGRAM_NAME == __FILE__
|
71
|
+
require File.expand_path('../../config/environment', __FILE__)
|
72
|
+
end
|
73
|
+
|
74
|
+
module ActiveRecord
|
75
|
+
class Base
|
76
|
+
def self.my_quote_columns(*column_names)
|
77
|
+
quoted_table_name = connection.quote_table_name(table_name)
|
78
|
+
column_names.map { |column_name| "#{ quoted_table_name }.#{ connection.quote_column_name(column_name) }" }.join(", ")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module ActiveRecord
|
84
|
+
module ConnectionAdapters #:nodoc:
|
85
|
+
class Column
|
86
|
+
def type_cast_with_f_object(value)
|
87
|
+
return value if value.is_a?(F)
|
88
|
+
type_cast_without_f_object(value)
|
89
|
+
end
|
90
|
+
|
91
|
+
alias_method_chain_once :type_cast, :f_object
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
class Relation
|
97
|
+
def build_where_with_f_object(*args)
|
98
|
+
if args.size == 1 && args[0].is_a?(Hash)
|
99
|
+
hash_conditions = args[0]
|
100
|
+
hash_conditions.each { |_, v| v.klass = klass if v.is_a?(F) }
|
101
|
+
end
|
102
|
+
|
103
|
+
build_where_without_f_object(*args)
|
104
|
+
end
|
105
|
+
|
106
|
+
alias_method_chain_once :build_where, :f_object
|
107
|
+
end
|
108
|
+
|
109
|
+
class Base
|
110
|
+
class << self
|
111
|
+
def sanitize_sql_hash_for_assignment_with_f_object(assignments)
|
112
|
+
f_assignments, normal_assignments = assignments.partition { |_, v| v.is_a?(F) }
|
113
|
+
|
114
|
+
f_sql = f_assignments.map do |attr, f_obj|
|
115
|
+
"#{connection.quote_column_name(attr)} = #{connection.quote_column_name(f_obj.attr_name)}"
|
116
|
+
end.join(", ")
|
117
|
+
|
118
|
+
normal_sql = sanitize_sql_hash_for_assignment_without_f_object(normal_assignments)
|
119
|
+
|
120
|
+
[(f_sql if f_sql.present?), (normal_sql if normal_sql.present?)].compact.join(", ")
|
121
|
+
end
|
122
|
+
|
123
|
+
alias_method_chain_once :sanitize_sql_hash_for_assignment, :f_object
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
module AttributeMethods
|
128
|
+
module Write
|
129
|
+
def write_attribute_with_f_object(attr_name, value)
|
130
|
+
write_attribute_without_f_object(attr_name, value)
|
131
|
+
|
132
|
+
# cancel number and any other type of conversions
|
133
|
+
if value.is_a?(F)
|
134
|
+
value.klass = self.class
|
135
|
+
@attributes[attr_name] = value
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
alias_method_chain_once :write_attribute, :f_object
|
140
|
+
end
|
141
|
+
|
142
|
+
module TimeZoneConversion
|
143
|
+
module ClassMethods
|
144
|
+
def define_method_attribute_with_f_object=(attr_name)
|
145
|
+
send(:define_method_attribute_without_f_object=, attr_name)
|
146
|
+
|
147
|
+
method_body, line = <<-EOV, __LINE__ + 1
|
148
|
+
def #{attr_name}_with_f_object=(time)
|
149
|
+
if time.is_a?(F)
|
150
|
+
time.klass = self.class
|
151
|
+
write_attribute(:#{attr_name}, time)
|
152
|
+
else
|
153
|
+
send(:#{attr_name}_without_f_object=, time)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
alias_method_chain_once :#{attr_name}=, :f_object unless respond_to?(:#{attr_name}_without_f_object=)
|
158
|
+
EOV
|
159
|
+
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
160
|
+
end
|
161
|
+
|
162
|
+
alias_method_chain_once :define_method_attribute=, :f_object
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
if $PROGRAM_NAME == __FILE__
|
169
|
+
class User < ActiveRecord::Base
|
170
|
+
end
|
171
|
+
|
172
|
+
require 'rspec/core'
|
173
|
+
require 'rspec/expectations'
|
174
|
+
require 'rspec/matchers'
|
175
|
+
|
176
|
+
Rspec.configure do |c|
|
177
|
+
c.mock_with :rspec
|
178
|
+
end
|
179
|
+
|
180
|
+
describe F do
|
181
|
+
Rspec::Matchers.define :end_with do |expected|
|
182
|
+
match do |actual|
|
183
|
+
actual.end_with?(expected)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
specify { User.where(:updated_at => F(:created_at)).to_sql.should
|
188
|
+
end_with("(`users`.`updated_at` = `users`.`created_at`)") }
|
189
|
+
|
190
|
+
specify { User.where(:updated_at => F(:created_at) + 1).to_sql.should
|
191
|
+
end_with("(`users`.`updated_at` = `users`.`created_at` + 1)") }
|
192
|
+
|
193
|
+
specify { User.where(:updated_at => F(:created_at) + F(:updated_at)).to_sql.should
|
194
|
+
end_with("(`users`.`updated_at` = `users`.`created_at` + `users`.`updated_at`)") }
|
195
|
+
|
196
|
+
specify { User.where(:updated_at => F(:created_at) + F(:updated_at)).to_sql.should
|
197
|
+
end_with("(`users`.`updated_at` = `users`.`created_at` + `users`.`updated_at`)") }
|
198
|
+
|
199
|
+
def update_sql(f_obj)
|
200
|
+
id_attr = User.scoped.arel_table.find_attribute_matching_name("id")
|
201
|
+
Arel::Update.new(User.scoped, id_attr => f_obj).to_sql.strip
|
202
|
+
end
|
203
|
+
|
204
|
+
specify { update_sql(F(:di)).should
|
205
|
+
end_with("SET `id` = `users`.`di`") }
|
206
|
+
|
207
|
+
specify { update_sql(F(:di) + 1).should
|
208
|
+
end_with("SET `id` = `users`.`di` + 1") }
|
209
|
+
|
210
|
+
specify { update_sql(F(:di) + F(:id)).should
|
211
|
+
end_with("SET `id` = `users`.`di` + `users`.`id`") }
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# Django Q object for Rails 2, 3
|
2
|
+
# http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
|
3
|
+
#
|
4
|
+
# Let's you build ORed, ANDed, and negated conditions without dropping to
|
5
|
+
# writing SQL.
|
6
|
+
#
|
7
|
+
# User.where(~Q(:user_id => nil))
|
8
|
+
#
|
9
|
+
# instead of User.where("user_id IS NOT NULL")
|
10
|
+
#
|
11
|
+
# User.where(Q(:user_id => nil) | Q(:id => nil))
|
12
|
+
#
|
13
|
+
# instead of User.where("user_id IS NULL OR id IS NULL")
|
14
|
+
#
|
15
|
+
# User.where(~(Q(:user_id => nil) & Q(:id => nil)))
|
16
|
+
#
|
17
|
+
# instead of User.where("user_id IS NOT NULL AND id IS NOT NULL")
|
18
|
+
#
|
19
|
+
# On Ruby 1.9 Object#! can be used to negate conditions
|
20
|
+
#
|
21
|
+
# User.where(!Q(:user_id => nil))
|
22
|
+
#
|
23
|
+
|
24
|
+
require "require_gist"; require_gist "383954/ea5a41269aac073b596b21fe392098827186a32b/alias_method_chain_once.rb", "a6f068593bb45fe6c9956205f672ac4a0c2e1671" # http://gist.github.com/383954
|
25
|
+
|
26
|
+
class Q
|
27
|
+
def |(other)
|
28
|
+
OrQ.new(self, other)
|
29
|
+
end
|
30
|
+
|
31
|
+
def &(other)
|
32
|
+
AndQ.new(self, other)
|
33
|
+
end
|
34
|
+
|
35
|
+
def ~
|
36
|
+
NotQ.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method "!", "~"
|
40
|
+
end
|
41
|
+
|
42
|
+
class BinaryQ < Q
|
43
|
+
attr_accessor :op1, :op2
|
44
|
+
|
45
|
+
def initialize(op1, op2)
|
46
|
+
self.op1, self.op2 = op1, op2
|
47
|
+
end
|
48
|
+
|
49
|
+
def empty?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class UnaryQ < Q
|
55
|
+
attr_accessor :op1
|
56
|
+
|
57
|
+
def initialize(*args)
|
58
|
+
self.op1 = (args.size == 1 ? args[0] : args)
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_q_sql(klass)
|
62
|
+
klass.send(:sanitize_sql, op1)
|
63
|
+
end
|
64
|
+
|
65
|
+
def empty?
|
66
|
+
op1.empty?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class AndQ < BinaryQ
|
71
|
+
def to_q_sql(klass)
|
72
|
+
"(#{ op1.to_q_sql(klass) }) AND (#{ op2.to_q_sql(klass) })"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class NotQ < UnaryQ
|
77
|
+
def to_q_sql(klass)
|
78
|
+
"(NOT (#{ op1.to_q_sql(klass) }))"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class OrQ < BinaryQ
|
83
|
+
def to_q_sql(klass)
|
84
|
+
"(#{ op1.to_q_sql(klass) }) OR (#{ op2.to_q_sql(klass) })"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def Q(*args)
|
89
|
+
UnaryQ.new(*args)
|
90
|
+
end
|
91
|
+
|
92
|
+
if $PROGRAM_NAME == __FILE__
|
93
|
+
require File.expand_path('../../config/environment', __FILE__)
|
94
|
+
end
|
95
|
+
|
96
|
+
module ActiveRecord
|
97
|
+
if defined?(Relation)
|
98
|
+
# Rails 3
|
99
|
+
class Relation
|
100
|
+
def build_where_with_q_object(*args)
|
101
|
+
if args.size == 1 && args[0].is_a?(Q)
|
102
|
+
return args[0].to_q_sql(klass)
|
103
|
+
end
|
104
|
+
|
105
|
+
build_where_without_q_object(*args)
|
106
|
+
end
|
107
|
+
|
108
|
+
alias_method_chain_once :build_where, :q_object
|
109
|
+
end
|
110
|
+
else
|
111
|
+
# Rails 2
|
112
|
+
class Base
|
113
|
+
class << self
|
114
|
+
def sanitize_sql_for_conditions_with_q_object(*args)
|
115
|
+
if args.size == 1 && args[0].is_a?(Q)
|
116
|
+
return args[0].to_q_sql(klass)
|
117
|
+
end
|
118
|
+
|
119
|
+
sanitize_sql_for_conditions_without_q_object(*args)
|
120
|
+
end
|
121
|
+
|
122
|
+
alias_method_chain_once :sanitize_sql_for_conditions, :q_object
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module ActiveRecord
|
129
|
+
class Base
|
130
|
+
def self.Q(*args)
|
131
|
+
UnaryQ.new(*args).to_q_sql(self)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if $PROGRAM_NAME == __FILE__
|
137
|
+
class User < ActiveRecord::Base
|
138
|
+
end
|
139
|
+
|
140
|
+
require 'rspec/expectations'
|
141
|
+
require 'rspec/core'
|
142
|
+
|
143
|
+
Rspec.configure do |c|
|
144
|
+
c.mock_with :rspec
|
145
|
+
end
|
146
|
+
|
147
|
+
describe Q do
|
148
|
+
Rspec::Matchers.define :be_like_conditions do |expected|
|
149
|
+
match do |actual|
|
150
|
+
actual.to_q_sql(User) == expected
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it { Q(:email => nil).should
|
155
|
+
be_like_conditions("`users`.`email` IS NULL") }
|
156
|
+
|
157
|
+
it { (~Q(:user_id => nil)).should
|
158
|
+
be_like_conditions("(NOT (`users`.`user_id` IS NULL))") }
|
159
|
+
|
160
|
+
it { (!Q(:user_id => nil)).should
|
161
|
+
be_like_conditions("(NOT (`users`.`user_id` IS NULL))") }
|
162
|
+
|
163
|
+
it { (User.Q(:is_avatar => nil)).should == "`users`.`is_avatar` IS NULL" }
|
164
|
+
|
165
|
+
it { (User.Q("name LIKE :like OR email LIKE :like", :like => "%#{ 42 }%")).should == "name LIKE '%42%' OR email LIKE '%42%'" }
|
166
|
+
|
167
|
+
it { (Q(:league_id => nil) & Q("path LIKE ?", "prefix/%")).should
|
168
|
+
be_like_conditions("(`users`.`league_id` IS NULL) AND (path LIKE 'prefix/%')") }
|
169
|
+
|
170
|
+
it { (Q(:to_account_id => 2) | Q(:from_account_id => 1)).should
|
171
|
+
be_like_conditions("(`users`.`to_account_id` = 2) OR (`users`.`from_account_id` = 1)") }
|
172
|
+
|
173
|
+
it { (!Q(:user_id => nil) & Q(:email => nil)).should
|
174
|
+
be_like_conditions("((NOT (`users`.`user_id` IS NULL)) AND (`users`.`email` IS NULL)") }
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# Formats the Exception so that it looks *familiar*,
|
2
|
+
# i.e. exactly like your interpreter does it.
|
3
|
+
#
|
4
|
+
# Port of MRI native `error_print` function.
|
5
|
+
class Exception
|
6
|
+
require "English"
|
7
|
+
|
8
|
+
def self.error_print(e = $ERROR_INFO)
|
9
|
+
warn_print = ""
|
10
|
+
backtrace = e.backtrace
|
11
|
+
backtrace = [ backtrace ] if backtrace.is_a?(String) # 1.9 returns single String for SystemStackError
|
12
|
+
|
13
|
+
warn_print << backtrace[0]
|
14
|
+
if e.is_a?(RuntimeError) && e.message.empty?
|
15
|
+
warn_print << ": unhandled exception\n"
|
16
|
+
else
|
17
|
+
if e.message.empty?
|
18
|
+
warn_print << ": #{ e.class.name }\n"
|
19
|
+
else
|
20
|
+
split_message = e.message.split("\n")
|
21
|
+
warn_print << ": "
|
22
|
+
if split_message.size == 1
|
23
|
+
warn_print << "#{ e.message } (#{ e.class.name })\n"
|
24
|
+
else
|
25
|
+
warn_print << split_message[0]
|
26
|
+
warn_print << " (#{ e.class.name })\n"
|
27
|
+
warn_print << split_message[1..-1].join("\n").chomp << "\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
len = backtrace.size
|
33
|
+
|
34
|
+
# int skip = eclass == rb_eSysStackError;
|
35
|
+
skip = e.is_a?(SystemStackError)
|
36
|
+
|
37
|
+
# #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
|
38
|
+
# #define TRACE_HEAD 8
|
39
|
+
# #define TRACE_TAIL 5
|
40
|
+
trace_head = 8
|
41
|
+
trace_tail = 5
|
42
|
+
trace_max = (trace_head + trace_tail + 5)
|
43
|
+
#
|
44
|
+
# for (i = 1; i < len; i++) {
|
45
|
+
i = 1
|
46
|
+
while i < len
|
47
|
+
# if (TYPE(ptr[i]) == T_STRING) {
|
48
|
+
# warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
|
49
|
+
# }
|
50
|
+
warn_print << "\tfrom %s\n" % e.backtrace[i]
|
51
|
+
|
52
|
+
# if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
|
53
|
+
if skip && i == trace_head && len > trace_max
|
54
|
+
# warn_printf("\t ... %ld levels...\n",
|
55
|
+
# len - TRACE_HEAD - TRACE_TAIL);
|
56
|
+
warn_print << "\t ... %d levels...\n" % (len - trace_head - trace_tail)
|
57
|
+
# i = len - TRACE_TAIL;
|
58
|
+
i = len - trace_tail
|
59
|
+
# }
|
60
|
+
end
|
61
|
+
# }
|
62
|
+
i += 1
|
63
|
+
end
|
64
|
+
warn_print
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
if $PROGRAM_NAME == __FILE__
|
70
|
+
if ARGV.empty?
|
71
|
+
# Main test suite runner
|
72
|
+
require "spec"
|
73
|
+
require "require_gist"; require_gist "371861/7dbcff4b266451b70cca183ce24917340587e8d3/shell_out.rb", "1e8bbc0ef3d1d078a4e57eb03225913c3a1e4fe5" # http://gist.github.com/371861
|
74
|
+
|
75
|
+
describe "Exception.error_print" do
|
76
|
+
include ShellOut
|
77
|
+
%w(normal
|
78
|
+
multiline
|
79
|
+
empty_message
|
80
|
+
non_empty_message
|
81
|
+
runtime_empty
|
82
|
+
runtime_non_empty
|
83
|
+
sys_stack).each do |type|
|
84
|
+
it "outputs the same message as the native interpreter does for #{ type } exception" do
|
85
|
+
native = shell_out("ruby #{ __FILE__ } native raise_#{ type }", :out => :return)
|
86
|
+
|
87
|
+
native.should include(__FILE__)
|
88
|
+
|
89
|
+
error_printed = shell_out("ruby #{ __FILE__ } error_print raise_#{ type }", :out => :return)
|
90
|
+
|
91
|
+
error_printed.should include(__FILE__)
|
92
|
+
|
93
|
+
error_printed.should == native
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
exit ::Spec::Runner::CommandLine.run
|
99
|
+
else
|
100
|
+
# Helper
|
101
|
+
def raise_normal
|
102
|
+
f10
|
103
|
+
end
|
104
|
+
|
105
|
+
def raise_multiline
|
106
|
+
raise "qwe\nasd\nzxc"
|
107
|
+
end
|
108
|
+
|
109
|
+
def raise_empty_message
|
110
|
+
raise ArgumentError, ""
|
111
|
+
end
|
112
|
+
|
113
|
+
def raise_non_empty_message
|
114
|
+
raise ArgumentError, "qwe"
|
115
|
+
end
|
116
|
+
|
117
|
+
def raise_runtime_empty
|
118
|
+
raise
|
119
|
+
end
|
120
|
+
|
121
|
+
def raise_runtime_non_empty
|
122
|
+
raise RuntimeError, "runtime non empty"
|
123
|
+
end
|
124
|
+
|
125
|
+
def raise_sys_stack
|
126
|
+
baz
|
127
|
+
end
|
128
|
+
|
129
|
+
# puts (0..20).map { |i| "def f#{i}() f#{i+1}(); end"}.join("\n")
|
130
|
+
def f0() f1(); end
|
131
|
+
def f1() f2(); end
|
132
|
+
def f2() f3(); end
|
133
|
+
def f3() f4(); end
|
134
|
+
def f4() f5(); end
|
135
|
+
def f5() f6(); end
|
136
|
+
def f6() f7(); end
|
137
|
+
def f7() f8(); end
|
138
|
+
def f8() f9(); end
|
139
|
+
def f9() f10(); end
|
140
|
+
def f10() f11(); end
|
141
|
+
def f11() f12(); end
|
142
|
+
def f12() f13(); end
|
143
|
+
def f13() f14(); end
|
144
|
+
def f14() f15(); end
|
145
|
+
def f15() f16(); end
|
146
|
+
def f16() f17(); end
|
147
|
+
def f17() f18(); end
|
148
|
+
def f18() f19(); end
|
149
|
+
def f19() f20(); end
|
150
|
+
def f20
|
151
|
+
raise(ArgumentError, "multi\nline\nerror")
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
def foo; bar; end; def bar; foo; end; def baz; foo; end;
|
156
|
+
|
157
|
+
class NonExistingException < Exception
|
158
|
+
end
|
159
|
+
|
160
|
+
begin
|
161
|
+
eval ARGV[1]
|
162
|
+
# we need to keep the same backtraces to make comparison adequate
|
163
|
+
# since NonExistingException will never be raised - the exception
|
164
|
+
# will propagate to the top level and interpreter will do it's job
|
165
|
+
rescue (ARGV[0] == "native" ? NonExistingException : Exception) => e
|
166
|
+
puts Exception.error_print
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Usage: ./gist_readme.rb source_file.rb [README.md]
|
4
|
+
#
|
5
|
+
# Extracts first comment block from source_file.rb into README.md file
|
6
|
+
#
|
7
|
+
#
|
8
|
+
raise "source_file should be specified" if ARGV.empty?
|
9
|
+
|
10
|
+
File.open(File.expand_path(File.join("../", ARGV[1] || "README.md") , __FILE__), "w") do |f|
|
11
|
+
first_comment = []
|
12
|
+
IO.read(File.expand_path(File.join("../", ARGV[0]), __FILE__)).each_line do |l|
|
13
|
+
if l =~ /\s*#/
|
14
|
+
first_comment << l.sub(/^\s*#\s/, "").rstrip
|
15
|
+
elsif !first_comment.empty?
|
16
|
+
break
|
17
|
+
end
|
18
|
+
end
|
19
|
+
f.write(first_comment.join("\n"))
|
20
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Check Thomas Sawyer take on the problem http://github.com/rubyworks/paramix
|
2
|
+
module IncludableWithOptions
|
3
|
+
class << self
|
4
|
+
attr_accessor :last_default_options
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.included(includable_with_options)
|
8
|
+
%w(string/methodize kernel/constant module/basename module/spacename).each { |facets_core_ext| require "facets/#{ facets_core_ext }" }
|
9
|
+
|
10
|
+
raise "IncludableWithOptions should be included by the Module" unless includable_with_options.instance_of?(Module)
|
11
|
+
|
12
|
+
options_class_var_name = "@@#{ includable_with_options.basename.methodize }_options"
|
13
|
+
|
14
|
+
unless IncludableWithOptions.last_default_options.nil?
|
15
|
+
includable_with_options.send(:class_variable_set, options_class_var_name, IncludableWithOptions.last_default_options)
|
16
|
+
IncludableWithOptions.last_default_options = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
context = Kernel.constant(includable_with_options.spacename)
|
20
|
+
|
21
|
+
option_setting_duplicator = <<-CODE
|
22
|
+
def #{ context != Kernel ? "self." : "" }#{ includable_with_options.basename }(options = nil)
|
23
|
+
m = Kernel.constant("#{ includable_with_options.name }").dup
|
24
|
+
m.send(:class_variable_set, "#{ options_class_var_name }", options)
|
25
|
+
m
|
26
|
+
end
|
27
|
+
CODE
|
28
|
+
|
29
|
+
context.module_eval(option_setting_duplicator)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def IncludableWithOptions(options = {})
|
34
|
+
m = Kernel.const_get(:IncludableWithOptions).dup
|
35
|
+
# Because of Ruby bug (?) model function +included+ won't be able to access @@default_options:
|
36
|
+
# http://redmine.ruby-lang.org/issues/show/3080
|
37
|
+
# m.send(:class_variable_set, :@@default_options, options[:default])
|
38
|
+
IncludableWithOptions.last_default_options = options[:default]
|
39
|
+
m
|
40
|
+
end
|
41
|
+
|
42
|
+
if $PROGRAM_NAME == __FILE__
|
43
|
+
|
44
|
+
module MyStuff
|
45
|
+
module SystemWithTweaks
|
46
|
+
include IncludableWithOptions(:default => {})
|
47
|
+
|
48
|
+
def system(*args)
|
49
|
+
puts "@@system_with_tweaks_options #{ @@system_with_tweaks_options }"
|
50
|
+
puts "Executing command: #{ args.join(" ") }" if @@system_with_tweaks_options[:echo]
|
51
|
+
result = Kernel.system(*args)
|
52
|
+
raise "Command #{ args.join(" ") } exited with a nonzero exit status" if @@system_with_tweaks_options[:raise_exceptions]
|
53
|
+
result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module MyStuff
|
59
|
+
class D
|
60
|
+
include MyStuff::SystemWithTweaks(:asd => 123)
|
61
|
+
|
62
|
+
def m
|
63
|
+
system "echo 'just echoing'"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
module SystemWithTweaks
|
70
|
+
include IncludableWithOptions(:default => { :echo => true })
|
71
|
+
|
72
|
+
def system(*args)
|
73
|
+
puts "Executing command: #{ args.join(" ") }" if @@system_with_tweaks_options[:echo]
|
74
|
+
result = Kernel.system(*args)
|
75
|
+
raise "Command #{ args.join(" ") } exited with a nonzero exit status" if @@system_with_tweaks_options[:raise_exceptions]
|
76
|
+
result
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class C
|
81
|
+
include SystemWithTweaks(:echo => true)
|
82
|
+
|
83
|
+
def m
|
84
|
+
system "ls"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module MyStuff
|
89
|
+
class B
|
90
|
+
include MyStuff::SystemWithTweaks(:raise_exceptions => true)
|
91
|
+
|
92
|
+
def m
|
93
|
+
system "does_not_exist"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
puts "Top level include with options"
|
99
|
+
C.new.m
|
100
|
+
|
101
|
+
puts "Namespaced include without options"
|
102
|
+
MyStuff::D.new.m
|
103
|
+
|
104
|
+
puts "Namespaced include with options"
|
105
|
+
MyStuff::B.new.m
|
106
|
+
end
|