vex 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/Manifest +112 -0
  2. data/Rakefile +53 -0
  3. data/VERSION +1 -0
  4. data/config/README +2 -0
  5. data/config/dependencies.rb +10 -0
  6. data/config/gem.yml +7 -0
  7. data/init.rb +36 -0
  8. data/lib/nokogiri/nokogiri_ext.rb +96 -0
  9. data/lib/vex.rb +5 -0
  10. data/lib/vex/action_controller.rb +4 -0
  11. data/lib/vex/action_controller/verify_action.rb +97 -0
  12. data/lib/vex/action_controller/whitelisted_actions.rb +45 -0
  13. data/lib/vex/active_record.rb +3 -0
  14. data/lib/vex/active_record/__init__.rb +0 -0
  15. data/lib/vex/active_record/advisory_lock.rb +11 -0
  16. data/lib/vex/active_record/advisory_lock/mysql_adapter.rb +16 -0
  17. data/lib/vex/active_record/advisory_lock/sqlite_adapter.rb +78 -0
  18. data/lib/vex/active_record/belongs_to_many.rb +143 -0
  19. data/lib/vex/active_record/find_by_extension.rb +70 -0
  20. data/lib/vex/active_record/gem.rb +8 -0
  21. data/lib/vex/active_record/lite_table.rb +139 -0
  22. data/lib/vex/active_record/lite_view.rb +140 -0
  23. data/lib/vex/active_record/mass_load.rb +65 -0
  24. data/lib/vex/active_record/mysql_backup.rb +21 -0
  25. data/lib/vex/active_record/plugins/default_value_for/LICENSE.TXT +19 -0
  26. data/lib/vex/active_record/plugins/default_value_for/README.rdoc +421 -0
  27. data/lib/vex/active_record/plugins/default_value_for/Rakefile +6 -0
  28. data/lib/vex/active_record/plugins/default_value_for/init.rb +91 -0
  29. data/lib/vex/active_record/plugins/default_value_for/test.rb +279 -0
  30. data/lib/vex/active_record/plugins/default_value_for/test.sqlite3 +0 -0
  31. data/lib/vex/active_record/random_id.rb +56 -0
  32. data/lib/vex/active_record/resolver.rb +49 -0
  33. data/lib/vex/active_record/serialize_hash.rb +125 -0
  34. data/lib/vex/active_record/to_html.rb +53 -0
  35. data/lib/vex/active_record/validate.rb +76 -0
  36. data/lib/vex/active_record/validation_error_ext.rb +68 -0
  37. data/lib/vex/base.rb +2 -0
  38. data/lib/vex/base/app.rb +75 -0
  39. data/lib/vex/base/array/at_random.rb +17 -0
  40. data/lib/vex/base/array/cross.rb +26 -0
  41. data/lib/vex/base/array/each_batch.rb +32 -0
  42. data/lib/vex/base/array/parallel_map.rb +98 -0
  43. data/lib/vex/base/deprecation.rb +41 -0
  44. data/lib/vex/base/enumerable/deep.rb +95 -0
  45. data/lib/vex/base/enumerable/enumerable_ext.rb +59 -0
  46. data/lib/vex/base/enumerable/progress.rb +71 -0
  47. data/lib/vex/base/filesystem/fast_copy.rb +61 -0
  48. data/lib/vex/base/filesystem/grep.rb +34 -0
  49. data/lib/vex/base/filesystem/lock.rb +43 -0
  50. data/lib/vex/base/filesystem/lock.rb.test.lck +0 -0
  51. data/lib/vex/base/filesystem/lock.rb.test.pid +1 -0
  52. data/lib/vex/base/filesystem/make_dirs.rb +94 -0
  53. data/lib/vex/base/filesystem/parse_filename.rb +36 -0
  54. data/lib/vex/base/filesystem/tmp_file.rb +87 -0
  55. data/lib/vex/base/filesystem/write.rb +43 -0
  56. data/lib/vex/base/hash/compact.rb +38 -0
  57. data/lib/vex/base/hash/cross.rb +117 -0
  58. data/lib/vex/base/hash/easy_access.rb +141 -0
  59. data/lib/vex/base/hash/ensure_keys.rb +18 -0
  60. data/lib/vex/base/hash/extract.rb +71 -0
  61. data/lib/vex/base/hash/extras.rb +62 -0
  62. data/lib/vex/base/hash/inspect.rb +17 -0
  63. data/lib/vex/base/hash/simple_access_methods.rb +74 -0
  64. data/lib/vex/base/invalid_argument/invalid_argument.rb +97 -0
  65. data/lib/vex/base/local_conf.rb +35 -0
  66. data/lib/vex/base/net/http_ext.rb +227 -0
  67. data/lib/vex/base/net/socket_ext.rb +43 -0
  68. data/lib/vex/base/object/insp.rb +123 -0
  69. data/lib/vex/base/object/multiple_attributes.rb +58 -0
  70. data/lib/vex/base/object/singleton_methods.rb +23 -0
  71. data/lib/vex/base/object/with_benchmark.rb +110 -0
  72. data/lib/vex/base/range_array.rb +40 -0
  73. data/lib/vex/base/range_ext.rb +28 -0
  74. data/lib/vex/base/safe_token.rb +156 -0
  75. data/lib/vex/base/string/string_ext.rb +136 -0
  76. data/lib/vex/base/thread/deferred.rb +52 -0
  77. data/lib/vex/base/thread/sleep.rb +11 -0
  78. data/lib/vex/base/time/date_ext.rb +12 -0
  79. data/lib/vex/boot.rb +40 -0
  80. data/lib/vex/boot/array.rb +22 -0
  81. data/lib/vex/boot/blank.rb +41 -0
  82. data/lib/vex/boot/string.rb +60 -0
  83. data/migration/create_request_log.rb +28 -0
  84. data/r.rb +35 -0
  85. data/script/console +19 -0
  86. data/script/rebuild +7 -0
  87. data/tasks/echoe.rake +52 -0
  88. data/tasks/validate_db.rake +14 -0
  89. data/test/ar.rb +30 -0
  90. data/test/auto.rb +31 -0
  91. data/test/base-tests/local_conf.rb +25 -0
  92. data/test/base.rb +2 -0
  93. data/test/boot.rb +3 -0
  94. data/test/config/local.defaults.yml +4 -0
  95. data/test/config/local.yml +8 -0
  96. data/test/test.sqlite3 +0 -0
  97. data/test/test.sqlite3.Class#create.lck +0 -0
  98. data/test/test.sqlite3.Class#create.lck.lck +0 -0
  99. data/test/test.sqlite3.Class#create.lck.pid +1 -0
  100. data/test/test.sqlite3.Class#create.pid +1 -0
  101. data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck +0 -0
  102. data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck.lck +0 -0
  103. data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck.pid +1 -0
  104. data/test/test.sqlite3.LiteView.make.holders__view_dummy.pid +1 -0
  105. data/test/test.sqlite3.vex.lck +0 -0
  106. data/test/test_helper.rb +49 -0
  107. data/test/tmp/copy.dat +1 -0
  108. data/test/tmp/lock.sqlite3 +0 -0
  109. data/test/tmp/lock.sqlite3.etest.lck +0 -0
  110. data/test/tmp/lock.sqlite3.etest.pid +1 -0
  111. data/test/tmp/somedata.dat +61 -0
  112. data/vex.gemspec +49 -0
  113. data/vex.tmproj +186 -0
  114. metadata +305 -0
@@ -0,0 +1,23 @@
1
+ class Object
2
+ module SingletonMethods
3
+ # returns the singleton class of an object
4
+ def singleton_class
5
+ class << self; self; end
6
+ end
7
+
8
+ # defines a method on an object
9
+ def define_object_method(name, &block)
10
+ singleton_class.send :define_method, name, &block
11
+ end
12
+ end
13
+
14
+ include SingletonMethods
15
+ end
16
+
17
+ module SingletonMethods::Etest
18
+ def test_singleton_methods
19
+ s = "s"
20
+ s.define_object_method :bla do "blabla" end
21
+ assert_equal("blabla", s.bla)
22
+ end
23
+ end if VEX_TEST == "base"
@@ -0,0 +1,110 @@
1
+ require "benchmark"
2
+
3
+ module Object::WithBenchmark
4
+
5
+ class BenchmarkProxy
6
+ def initialize(host, *args)
7
+ @host = host
8
+
9
+ if args.length == 1 && args.first.is_a?(String)
10
+ @out, @label = nil, args.first
11
+ else
12
+ @out, @label = *args
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def report(msg)
19
+ if !@out
20
+ logger = @host.respond_to?(:logger) && @host.logger || App.logger
21
+
22
+ logger.warn(msg)
23
+ STDERR.puts(msg) if App.env == "development"
24
+ elsif @out.respond_to?(:warn)
25
+ @out.warn(msg)
26
+ elsif @out.respond_to?(:<<)
27
+ @out << "#{msg}\n"
28
+ end
29
+ end
30
+
31
+ def method_missing(*args, &block)
32
+ result = ex = nil
33
+
34
+ realtime = Benchmark.realtime do
35
+ begin
36
+ result = @host.__send__(*args, &block)
37
+ rescue
38
+ ex = $!
39
+ end
40
+ end
41
+
42
+ msg = "#{@label || "benchmarked"}: #{ex && "EXCEPTION #{ex} after "}#{"%.2f secs" % realtime}"
43
+
44
+ report(msg)
45
+
46
+ raise ex if ex
47
+ result
48
+ end
49
+ end
50
+
51
+ def no_benchmark(*args, &block)
52
+ block_given? ? yield : self
53
+ end
54
+
55
+ def benchmark(*args, &block)
56
+ count = args.last.is_a?(Fixnum) ? args.pop : 1
57
+
58
+ proxy = BenchmarkProxy.new self, *args, &block
59
+ return proxy unless block_given?
60
+ return proxy.yield(&block) if count <= 1
61
+ return proxy.yield do
62
+ count.times(&block)
63
+ end
64
+ end
65
+
66
+ def yield(&block); yield; end
67
+ end
68
+
69
+ Object.send :include, Object::WithBenchmark
70
+
71
+ module Object::WithBenchmark::Etest
72
+ def test_results
73
+ App.logger.stubs(:warn).returns(nil)
74
+
75
+ assert_equal 6, "string".benchmark.length
76
+ assert_raise(NoMethodError) {
77
+ "string".benchmark.you_dont_know_me
78
+ }
79
+ end
80
+
81
+ def test_benchmark
82
+ s = ""
83
+ assert_equal 6, "string".benchmark(s, "").length
84
+ assert s.length > 0
85
+ end
86
+
87
+ def test_label
88
+ App.logger.stubs(:warn).returns(nil)
89
+
90
+ assert_equal 6, "string".benchmark("oh! a label!").length
91
+ end
92
+
93
+ class DL
94
+ attr :msg
95
+ def warn(s);
96
+ @msg = s
97
+ end
98
+ end
99
+
100
+ def test_logger
101
+ s = "string"
102
+
103
+ def s.logger; @logger ||= DL.new; end
104
+ assert s.respond_to?(:logger)
105
+ assert s.logger.msg.blank?
106
+
107
+ assert_equal 6, s.benchmark.length
108
+ assert !s.logger.msg.blank?
109
+ end
110
+ end if VEX_TEST == "base"
@@ -0,0 +1,40 @@
1
+ class RangeArray < Array
2
+ def initialize(array)
3
+ min = max = nil
4
+
5
+ array.each do |i|
6
+ if min
7
+ if i >= min && i <= max then next
8
+ elsif i == min-1 then min = i
9
+ elsif i == max+1 then max = i
10
+ else
11
+ push min, max
12
+ min = max = i
13
+ end
14
+ else
15
+ min = max = i
16
+ end
17
+ end
18
+
19
+ push min, max if min
20
+ end
21
+
22
+ def push(min, max)
23
+ super min == max ? min : min..max
24
+ end
25
+ end
26
+
27
+ module RangeArray::Etest
28
+ def ra(*array)
29
+ RangeArray.new array
30
+ end
31
+
32
+ def test_range_array
33
+ assert_equal [1..3], ra(1, 2, 3)
34
+ assert_equal [1..3, 5..6], ra(1, 2, 3, 5, 6)
35
+ assert_equal [1..3, 5..6, 8], ra(1, 2, 3, 5, 6, 8)
36
+ assert_equal [1..2, 7, 3, 5..6, 8], ra(1, 2, 7, 3, 5, 6, 8)
37
+ assert_equal [1..2, 7, 3, 5..6, 8, 4], ra(1, 2, 7, 3, 5, 6, 8, 4)
38
+ assert_equal [1..2, 7, 3, 5..6, 8, 4, -3], ra(1, 2, 7, 3, 5, 6, 8, 4, -3)
39
+ end
40
+ end if VEX_TEST == "base"
@@ -0,0 +1,28 @@
1
+ class Range
2
+ def limit(value)
3
+ if value < first then first
4
+ elsif value > last then last
5
+ else value
6
+ end
7
+ end
8
+ end
9
+
10
+ class Numeric
11
+ def limit(range)
12
+ range.limit(self)
13
+ end
14
+ end
15
+
16
+ module Range::Etest
17
+ def test_range
18
+ assert_equal 1, (1..3).limit(-1)
19
+ assert_equal 1, (1..3).limit(1)
20
+ assert_equal 2, (1..3).limit(2)
21
+ assert_equal 3, (1..3).limit(3)
22
+ assert_equal 3, (1..3).limit(4)
23
+ end
24
+
25
+ def test_numeric
26
+ assert_equal 1, -1.limit(1..3)
27
+ end
28
+ end if VEX_TEST == "base"
@@ -0,0 +1,156 @@
1
+ require 'digest/sha1'
2
+ require 'json'
3
+ require 'base64'
4
+
5
+ module SafeToken
6
+ CipherError = if defined?(OpenSSL::Cipher::CipherError)
7
+ OpenSSL::Cipher::CipherError
8
+ else
9
+ OpenSSL::CipherError
10
+ end
11
+
12
+ class InvalidToken < RuntimeError; end
13
+ class TokenTooLong < InvalidToken; end
14
+ class TokenExpired < InvalidToken
15
+ attr :expires
16
+ def initialize(expires)
17
+ @expires = expires
18
+ end
19
+
20
+ def to_s
21
+ "token expired at #{expires}"
22
+ end
23
+ end
24
+ private
25
+
26
+ DEFAULTS = {
27
+ :secret => "46a348efe02807c999d69709abdbcd1b",
28
+ :limit => 800, # This should be safe for an URL
29
+ :crypt => false
30
+ }
31
+
32
+ def self.hash!(opts, data)
33
+ Digest::SHA1.hexdigest data
34
+ end
35
+
36
+ def self.aes(encrypt_or_decrypt, data, opts)
37
+ return data if opts[:crypt] == false
38
+
39
+ # get the password and make sure it is long enough for the algorithm to work
40
+ secret = opts[:crypt].is_a?(String) ? opts[:crypt] : opts[:secret]
41
+ secret = Digest::SHA1.hexdigest(secret)
42
+
43
+ c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
44
+ c.send encrypt_or_decrypt
45
+ c.key = secret
46
+ s = c.update(data)
47
+ s << c.final
48
+ end
49
+
50
+ def self.encode64(s)
51
+ Base64.encode64(s).gsub("\n", '').gsub("=", '-')
52
+ end
53
+
54
+ def self.decode64(s)
55
+ Base64.decode64(s.gsub("-", '='))
56
+ end
57
+
58
+ def self.limit!(s, opts)
59
+ if opts[:limit] && s.length > opts[:limit]
60
+ raise TokenTooLong, "Token too long: (#{s.length} bytes, allowed are #{opts[:limit]})"
61
+ end
62
+ s
63
+ end
64
+
65
+ public
66
+
67
+ def self.generate(data, opts = {})
68
+ opts = DEFAULTS.dup.update(opts)
69
+ expires = opts[:expires].to_i if opts[:expires]
70
+
71
+ data = data.to_json
72
+
73
+ hash = hash!(opts, "#{opts[:secret]}-#{expires}:#{data}")
74
+ s = "sha1:#{hash}:#{expires}:#{data}"
75
+
76
+ s = aes(:encrypt, s, opts)
77
+ s = encode64(s)
78
+ limit!(s, opts)
79
+ end
80
+
81
+ def self.validate(s, opts = {})
82
+ opts = DEFAULTS.dup.update(opts)
83
+
84
+ begin
85
+ s = decode64(s)
86
+ s = aes(:decrypt, s, opts)
87
+ rescue SafeToken::CipherError
88
+ raise InvalidToken, "Invalid token encryption: #{$!}"
89
+ end
90
+
91
+ raise InvalidToken, "Invalid token syntax" unless s =~ /^([^:]*):([^:]*):([^:]*):(.*)/
92
+
93
+ method, hash, expires, data = $1, $2, $3, $4
94
+
95
+ unless hash!(opts, "#{opts[:secret]}-#{expires}:#{data}") == hash
96
+ raise InvalidToken, "Invalid token #{s}"
97
+ end
98
+
99
+ if !expires.empty?
100
+ expires = Time.at(expires.to_i)
101
+ raise TokenExpired, expires if expires < Time.now
102
+ end
103
+
104
+ JSON.parse(data)
105
+ end
106
+ end
107
+
108
+ module SafeToken::Etest
109
+ def data
110
+ {"a" => "123232", "b" => { "c" => [ 1, 2, "d" ]}}
111
+ end
112
+
113
+ def test_expiration
114
+ token = SafeToken.generate(data, :crypt => false, :expires => Time.now-10)
115
+ assert_raise(SafeToken::TokenExpired) {
116
+ begin
117
+ SafeToken.validate(token)
118
+ rescue
119
+ assert $!.to_s =~ /expired/
120
+ raise
121
+ end
122
+ }
123
+
124
+ token = SafeToken.generate(data, :crypt => false, :expires => Time.now+10)
125
+ assert_equal data, SafeToken.validate(token)
126
+ end
127
+
128
+ def test_token
129
+ token = SafeToken.generate(data, :crypt => false)
130
+ assert_equal data, SafeToken.validate(token)
131
+ end
132
+
133
+ def test_token_w_crypt
134
+ token = SafeToken.generate(data, :crypt => true)
135
+ assert_equal data, SafeToken.validate(token, :crypt => true)
136
+ end
137
+
138
+ def test_token_w_crypt2
139
+ token1 = SafeToken.generate(data, :crypt => "secret")
140
+ token2 = SafeToken.generate(data, :crypt => true)
141
+ token3 = SafeToken.generate(data, :crypt => false)
142
+ assert_not_equal(token1, token2)
143
+ assert_not_equal(token1, token3)
144
+ assert_not_equal(token2, token3)
145
+ end
146
+
147
+ def test_invalid_enc_parameters
148
+ token = SafeToken.generate(data, :crypt => true)
149
+
150
+ OpenSSL::Cipher::Cipher.any_instance.stubs(:update).raises(SafeToken::CipherError)
151
+ assert_raise(SafeToken::InvalidToken) {
152
+ assert_equal data, SafeToken.validate(token, :crypt => true)
153
+ }
154
+ end
155
+ end if VEX_TEST == "base"
156
+
@@ -0,0 +1,136 @@
1
+ module StringExt
2
+ def constantize?
3
+ constantize
4
+ rescue LoadError, NameError
5
+ STDERR.puts $!.to_s
6
+ end
7
+
8
+ def uri?
9
+ !!(self =~ /^[a-z][a-z]+:/)
10
+ end
11
+
12
+ def unhtml
13
+ return self if blank?
14
+ s = Sanitize.clean(self)
15
+ HTMLEntities.new.decode(s)
16
+ end
17
+
18
+ # truncate :length => 30, :omission => "…"
19
+ def truncate(*args)
20
+ opts = if args.length == 1 && args.first.is_a?(Hash)
21
+ args.first
22
+ else
23
+ args.inject({}) do |hash, arg|
24
+ key = case arg
25
+ when Fixnum then :length
26
+ when String then :omission
27
+ end
28
+
29
+ invalid_argument!(arg) if key.nil? || hash[key]
30
+
31
+ hash.update key => arg
32
+ end
33
+ end
34
+
35
+ _truncate(opts)
36
+ end
37
+
38
+ def _truncate(opts)
39
+ opts = { :length => opts, :omission => "…" } unless opts.is_a?(Hash)
40
+ max_length = opts[:length] || 30
41
+ omission = opts[:omission] || "…"
42
+
43
+ #
44
+ # Treat multibytes differently
45
+ if respond_to?(:mb_chars)
46
+ l = max_length - omission.mb_chars.length
47
+ if mb_chars.length > max_length
48
+ return (mb_chars[0...l] + omission).to_s
49
+ end
50
+ else
51
+ l = max_length - omission.length
52
+ if length > max_length
53
+ return self[0...l] + omission
54
+ end
55
+ end
56
+
57
+ self
58
+ end
59
+
60
+ def truncate!(opts = {})
61
+ replace truncate(opts)
62
+ end
63
+
64
+ def word_wrap(line_len=100)
65
+ lines = split("\n")
66
+ lines.map { |line| StringExt.word_wrap(line, line_len) }.join("\n")
67
+ end
68
+
69
+ def self.word_wrap(line, line_len)
70
+ r = []
71
+ while line.length > line_len
72
+ # find last space in the first line_len characters. Failing that we
73
+ # take the *first* (sic!) space in the entire line.
74
+ firstline = line[0..line_len]
75
+ space_idx = firstline.rindex(/\s/) || line.index(/\s/, line_len)
76
+
77
+ if !space_idx
78
+ r << line
79
+ line = ""
80
+ else
81
+ r << line[0...space_idx]
82
+ line = line[space_idx+1..-1]
83
+ end
84
+ end
85
+
86
+ r << line unless line.blank?
87
+ r.join("\n")
88
+ end
89
+ end
90
+
91
+ String.send :include, StringExt
92
+
93
+ module StringExt::Etest
94
+ def test_unhtml
95
+ assert_equal("", "".unhtml)
96
+ assert_equal("hjghjg", "<p>hjghjg</p>".unhtml)
97
+ assert_equal("&auml", "&auml".unhtml)
98
+ assert_equal("ä", "&auml;".unhtml)
99
+ end
100
+
101
+ # truncate :length => 30, :omission => "..."
102
+ def test_truncate
103
+ assert_equal("", "".truncate)
104
+ assert_equal("123456", "123456".truncate)
105
+ assert_equal("123…", "1234567".truncate(:length => 6))
106
+ assert_equal("123…", "1234567".truncate(6))
107
+ assert_equal("12345~", "1234567".truncate(6, "~"))
108
+ end
109
+
110
+ def test_truncate!
111
+ s = "1234567"
112
+
113
+ assert_equal "123…", s.truncate(6)
114
+ assert_equal "1234567", s
115
+
116
+ assert_equal "123…", s.truncate!(6)
117
+ assert_equal "123…", s
118
+ end
119
+
120
+ def test_word_wrap
121
+ assert_equal "abcdef\nghijkl", "abcdef ghijkl".word_wrap(8)
122
+ assert_equal "abc def\nghijkl", "abc def ghijkl".word_wrap(8)
123
+ assert_equal "abcdefghijkl", "abcdefghijkl".word_wrap(8)
124
+ end
125
+
126
+ def test_uri
127
+ assert_equal true, "http://".uri?
128
+ assert_equal false, "//".uri?
129
+ assert_equal false, "c:\\x\\y".uri?
130
+ end
131
+
132
+ def test_constantize
133
+ assert_equal String, "String".constantize?
134
+ assert_equal nil, "I::Dont::Know::This".constantize?
135
+ end
136
+ end if VEX_TEST == "base"