dolzenko 0.0.10 → 0.0.11
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.
- 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
|