vex 0.2

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.
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,35 @@
1
+ class LocalConf < Hash
2
+ include Hash::EasyAccess
3
+
4
+ def initialize(file)
5
+ r1 = load file.sub(/\.yml$/, ".defaults.yml")
6
+ r2 = load file, App.env
7
+
8
+ return if r1 || r2
9
+
10
+ raise Errno::ENOENT,
11
+ "Missing configuration file #{App.root}/config/#{file.sub(/\.yml$/, "")}{.defaults}.yml}"
12
+ end
13
+
14
+ private
15
+
16
+ def load(file, key = nil)
17
+ data = YAML::load_file("#{App.root}/config/#{file}")
18
+ data = data[key] if data && key
19
+ data.each { |k,v| update k.to_sym => v } if data
20
+ true
21
+ rescue Errno::ENOENT
22
+ false
23
+ end
24
+
25
+ def method_missing(sym, *args, &block)
26
+ return super unless args.empty? && !block_given? && sym.to_s =~ /(.*)\?/
27
+ !fetch($1.to_sym).blank?
28
+ rescue IndexError
29
+ false
30
+ end
31
+
32
+ def self.method_missing(sym, *args, &block)
33
+ App.local_conf.send sym, *args, &block
34
+ end
35
+ end if VEX_TEST == "base"
@@ -0,0 +1,227 @@
1
+ require "net/http"
2
+ require "net/https"
3
+
4
+ module Net::HTTPExt; end
5
+
6
+ Net.extend Net::HTTPExt
7
+
8
+ #
9
+ # This adds Net.get, Net.head, Net.post
10
+ module Net::HTTPExt
11
+ REDIRECTION_LIMIT = 10
12
+
13
+ DEFAULT_OPTIONS = {
14
+ :redirect => 10 # MAX # of redirection
15
+ }
16
+
17
+ # This is a combination of a string (for the response body) and
18
+ # of a "hash" for the response header
19
+ class Response < String
20
+ class Headers
21
+ attr :code, true
22
+
23
+ def initialize(response)
24
+ @headers = response.instance_variable_get "@header"
25
+ end
26
+
27
+ def method_missing(sym, *args, &block)
28
+ return super unless args.empty? && !block_given?
29
+ self[sym]
30
+ end
31
+
32
+ def [](key)
33
+ r = @headers[key.to_s.downcase.gsub("_", "-")]
34
+ raise "huh?" unless r.is_a?(Array)
35
+ r.length <= 1 ? r.first : r
36
+ end
37
+ end
38
+
39
+ attr :response
40
+ attr :headers
41
+
42
+ def code; Integer(response.code); end
43
+ def good?; code >= 200 && code < 300; end
44
+ def message; response.message; end
45
+
46
+ def initialize(response)
47
+ super(response.body) if response.body
48
+ @response, @headers = response, Headers.new(response)
49
+ end
50
+ end
51
+
52
+ # POST request
53
+ def post(url, body, opts = {})
54
+ http :post, url, body, opts
55
+ end
56
+
57
+ # HEAD request
58
+ def head(url, opts = {})
59
+ http :head, url, nil, opts
60
+ end
61
+
62
+ # GET request
63
+ def get(url, opts = {})
64
+ http :get, url, nil, opts
65
+ end
66
+
67
+ def exists?(url, opts = {})
68
+ r = Net.head(url, opts)
69
+ r.code >= 200 && r.code < 300
70
+ end
71
+
72
+ alias :exist? :exists?
73
+
74
+ HEADERS_KEY = :"net:http_ext:preprocessors:headers"
75
+
76
+ def headers
77
+ Thread.current[HEADERS_KEY] ||= {}
78
+ end
79
+
80
+ def headers=(h)
81
+ Thread.current[HEADERS_KEY] = h
82
+ end
83
+
84
+ def with_headers(scope, &block)
85
+ old = headers
86
+ self.headers = headers.dup.update scope
87
+ yield
88
+ ensure
89
+ self.headers = old
90
+ end
91
+
92
+ private
93
+
94
+ def adjust_request!(verb, path, h, body)
95
+ headers.each do |k,v|
96
+ k = k.to_s
97
+
98
+ if v.respond_to?(:call)
99
+ v.call(verb, path, h, body)
100
+ elsif v.nil?
101
+ h.delete k
102
+ h.delete k.to_sym
103
+ else
104
+ h[k] ||= v
105
+ end
106
+ end
107
+ end
108
+
109
+ def http(verb, url, body, opts, &block)
110
+ # -- timeout handling
111
+ if timeout = opts.delete(:timeout)
112
+ begin
113
+ return Timeout.timeout(timeout) { http(verb, url, body, opts, &block) }
114
+ rescue Timeout::Error
115
+ return nil
116
+ end
117
+ end
118
+
119
+ headers = DEFAULT_OPTIONS.dup.update(opts)
120
+ redirect = headers.delete :redirect
121
+
122
+ r = do_http verb, url, body, headers, redirect, &block
123
+ r.headers.code = r.code
124
+
125
+ verb != :head ? r : r.headers
126
+ end
127
+
128
+ # connects to a HTTP server, yields the URI and the HTTP connection
129
+ def do_http(verb, url, body, headers={}, redirect = nil, &block)
130
+ # -- connect to the server
131
+ uri = url.is_a?(URI) ? url : URI.parse(url)
132
+
133
+ connection = Net::HTTP.new(uri.host, uri.port)
134
+ connection.use_ssl = uri.scheme == "https"
135
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
136
+
137
+ invalid_argument!("Invalid URL", url) unless %w(https http).include?(uri.scheme)
138
+
139
+ # -- do whatever
140
+ connection.start do |c|
141
+ adjust_request! verb, uri.request_uri, headers, body
142
+
143
+ args = [ ]
144
+ args << "request_#{verb}"
145
+ args << uri.request_uri
146
+ args << body if verb == :post || verb == :put
147
+ args << headers
148
+
149
+ response = connection.send *args
150
+
151
+ if !response.is_a?(Net::HTTPRedirection) || !redirect
152
+ next Response.new(response)
153
+ end
154
+
155
+ raise "Reached maximum number of redirections" if redirect <= 0
156
+
157
+ do_http verb == :head ? :head : :get,
158
+ redirection_url(url, response['location']),
159
+ nil,
160
+ headers,
161
+ redirect - 1
162
+ end
163
+ ensure
164
+ connection.finish if connection && connection.started?
165
+ end
166
+
167
+ #
168
+ # fix non default responses. Magento does this, sometimes...
169
+ def redirection_url(uri, location)
170
+ return location if URI.parse(location).scheme rescue nil
171
+ raise "Cannot redirect to URI #{location}" unless uri.to_s =~ /^((.*?)\/\/(.*?)\/)/
172
+ $1 + location.gsub(/^\/+/, "")
173
+ end
174
+ end
175
+
176
+ module Net::HTTPExt::Etest
177
+ def test_w_google_w_redirection
178
+ return unless Socket.online?
179
+
180
+ google = Net.get("http://www.google.com")
181
+ assert google =~ /<title>Google/
182
+ assert google.headers["Content-Type"] =~ /text\/html/
183
+ assert google.headers.content_type =~ /text\/html/
184
+ end
185
+
186
+ def test_w_google_wo_redirection
187
+ return unless Socket.online?
188
+
189
+ google = Net.get("http://www.google.com", :redirect => false)
190
+ assert_equal(302 , google.code)
191
+ assert google.headers["Content-Type"] =~ /text\/html/
192
+ assert google.headers.content_type =~ /text\/html/
193
+ end
194
+
195
+ def test_w_google
196
+ return unless Socket.online?
197
+
198
+ assert Net.exists?("http://www.google.de")
199
+ assert Net.exist?("http://www.google.de")
200
+
201
+ google = Net.get("http://www.google.de")
202
+ assert google =~ /<title>Google/
203
+ assert google.headers["Content-Type"] =~ /text\/html/
204
+ assert google.headers.content_type =~ /text\/html/
205
+ end
206
+
207
+ def test_w_google_timeout
208
+ return unless Socket.online?
209
+
210
+ google = Net.get("http://www.google.de", :timeout => 0.01)
211
+ assert_equal(nil, google)
212
+ end
213
+
214
+ def test_w_google_adjusted_headers
215
+ return unless Socket.online?
216
+
217
+ Net.with_headers :x_abc => "Test ABC" do
218
+ assert_equal("Test ABC", Net.headers[:x_abc])
219
+ assert Net.exists?("http://www.google.de")
220
+ Net.with_headers :x_abc => nil do
221
+ assert_equal(nil, Net.headers[:x_abc])
222
+ end
223
+ assert_equal("Test ABC", Net.headers[:x_abc])
224
+ end
225
+ end
226
+ end if VEX_TEST == "base"
227
+
@@ -0,0 +1,43 @@
1
+ require 'socket'
2
+
3
+ #
4
+ # see http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
5
+ #
6
+ class Socket
7
+ #
8
+ # Parameters:
9
+ #
10
+ # * when_talking_to: returns my IP when talking to that host.
11
+ # * when_talking_to: returns my IP when talking to that host.
12
+
13
+ # do_raise is mainly for test purposes
14
+ def self.local_ip(when_talking_to = nil)
15
+ when_talking_to ||= '64.233.187.99'
16
+ begin
17
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
18
+
19
+ UDPSocket.open do |s|
20
+ s.connect when_talking_to, 1
21
+ s.addr.last
22
+ end
23
+ rescue
24
+ "127.0.0.1" # not connected to the funny wide web?
25
+ ensure
26
+ Socket.do_not_reverse_lookup = orig
27
+ end
28
+ end
29
+
30
+ def self.online?
31
+ local_ip != "127.0.0.1"
32
+ end
33
+ end
34
+
35
+ module Socket::Etest
36
+ def test_returns_127_locally
37
+ require 'ipaddr'
38
+ local_net = IPAddr.new("127.0.0.0/24")
39
+ %w(127.0.0.1 127.0.0.2 localhost).each do |ip|
40
+ assert(local_net.include?(IPAddr.new(Socket.local_ip(ip))))
41
+ end
42
+ end
43
+ end if VEX_TEST == "base"
@@ -0,0 +1,123 @@
1
+ #
2
+ # short inspect method on all objects.
3
+ #
4
+ # "abcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnop".insp
5
+ # -> "abcdefghijklmnopabcdefghijk..."
6
+ # Model.find(1).insp
7
+ # -> "<Model#1>"
8
+
9
+ class Object
10
+ def insp
11
+ body = "#{insp_body}"
12
+ body = ": #{body}" unless body.empty?
13
+ "#{insp_head}#{body}#{insp_close}"
14
+ end
15
+
16
+ private
17
+
18
+ def insp_head; "<#{self.class}@#{self.object_id}"; end
19
+ def insp_body; end
20
+ def insp_close; ">"; end
21
+ end
22
+
23
+ [ Numeric, TrueClass, FalseClass, NilClass, Symbol, Module ].each do |klass|
24
+ klass.send :alias_method, :insp, :inspect
25
+ end
26
+
27
+ class String
28
+ INSP_TRUNCATE_LEN = 30
29
+
30
+ def insp
31
+ return inspect unless length > INSP_TRUNCATE_LEN
32
+
33
+ l = INSP_TRUNCATE_LEN - 3
34
+ (self[0...l].to_s + "...").inspect
35
+ end
36
+ end
37
+
38
+ if defined?(ActiveRecord)
39
+ class ActiveRecord::Base
40
+ private
41
+
42
+ def insp_head; "<#{self.class}##{self.id}"; end
43
+ end
44
+ end
45
+
46
+ class Hash
47
+ def insp
48
+ self.class == Hash && instance_variables.empty? ? insp_body : super
49
+ end
50
+
51
+ private
52
+
53
+ INSP_TRUNCATE_LEN = 10
54
+
55
+ def insp_body
56
+ body = to_a.sort { |a,b|
57
+ a <=> b rescue a.to_s <=> b.to_s
58
+ }
59
+
60
+ if length > INSP_TRUNCATE_LEN
61
+ body = body[0...INSP_TRUNCATE_LEN]
62
+ more = ", ... (#{length - INSP_TRUNCATE_LEN} more)"
63
+ end
64
+
65
+ "{#{body.map { |k,v| "#{k.insp} => #{v.insp}"}.join(", ")}#{more}}"
66
+ end
67
+ end
68
+
69
+ class Array
70
+ def insp
71
+ self.class == Array && instance_variables.empty? ? insp_body : super
72
+ end
73
+
74
+ private
75
+
76
+ INSP_TRUNCATE_LEN = 20
77
+
78
+ def insp_body
79
+ if length > INSP_TRUNCATE_LEN
80
+ body = self[0...INSP_TRUNCATE_LEN]
81
+ more = ", ... (#{length - INSP_TRUNCATE_LEN} more)"
82
+ end
83
+
84
+ "[#{(body || self).map(&:insp).join(", ")}#{more}]"
85
+ end
86
+ end
87
+
88
+ module Insp; end
89
+
90
+ module Insp::Etest
91
+ def test_insp_array
92
+ assert_equal("[1, 2]", [1,2].insp)
93
+ assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ... (10 more)]", (1..30).to_a.insp)
94
+ end
95
+
96
+ def test_insp_hash
97
+ assert_equal("{}", {}.insp)
98
+
99
+ h = (1..30).to_a.inject({}) do |hash, id|
100
+ hash.update id => id*id
101
+ end
102
+ assert_equal "{1 => 1, 2 => 4, 3 => 9, 4 => 16, 5 => 25, 6 => 36, 7 => 49, 8 => 64, 9 => 81, 10 => 100, ... (20 more)}",
103
+ h.insp
104
+ end
105
+
106
+ def test_insp_string
107
+ s = "123"
108
+ assert_equal(s.insp, s.inspect)
109
+ s = (s * 100).insp
110
+ assert s.ends_with?("...\"")
111
+ assert s.length < 50
112
+ end
113
+
114
+ class X
115
+ def initialize
116
+ @x = "x"
117
+ end
118
+ end
119
+
120
+ def test_insp_obj
121
+ assert X.new.insp =~ /Insp::Etest::X/
122
+ end
123
+ end if VEX_TEST == "base"
@@ -0,0 +1,58 @@
1
+ class Module
2
+ module MultipleAttributes
3
+ def attributes(*args)
4
+ writable_flag = args.last
5
+ if writable_flag != true && writable_flag != false
6
+ writable_flag = false
7
+ else
8
+ args.pop
9
+ end
10
+
11
+ args.each do |arg|
12
+ attr arg, writable_flag
13
+ end
14
+ end
15
+ end
16
+
17
+ include MultipleAttributes
18
+ end
19
+
20
+ module Module::MultipleAttributes::Etest
21
+ class X
22
+ attributes :a
23
+ attributes :b, :c
24
+
25
+ attributes :d, :e, true
26
+
27
+ def initialize
28
+ @a = "a"
29
+ @b = "b"
30
+ @c = "c"
31
+ @d = "d"
32
+ @e = "e"
33
+ end
34
+ end
35
+
36
+ def test_ma
37
+ x = X.new
38
+ assert_equal %w(a b c d e), [ x.a, x.b, x.c, x.d, x.e ]
39
+
40
+ assert_raise(NoMethodError) {
41
+ x.a = 1
42
+ }
43
+
44
+ assert_raise(NoMethodError) {
45
+ x.b = 1
46
+ }
47
+
48
+ assert_raise(NoMethodError) {
49
+ x.c = 1
50
+ }
51
+
52
+ x.d = 1
53
+ x.e = 2
54
+
55
+ assert_equal 1, x.d
56
+ assert_equal 2, x.e
57
+ end
58
+ end if VEX_TEST == "base"