rails2ext 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ something_else.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,2 @@
1
+ = Version 0.0.1
2
+ * First release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rails2ext.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ # Rails2Ext
2
+
3
+ This gem is intended to collect all sort of **Rails 2.3.x** extensions that are not (yet?) present in the official repo.
4
+ Its structure mimic the original gems structure, so developers should feel at home browsing/extending it.
5
+ There is not much right now, but it could grow in size.
6
+
7
+ # Tests
8
+
9
+ Run
10
+
11
+ rake
12
+
13
+ to run the rspec test suite.
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'bundler/gem_tasks'
5
+ require 'rspec/core/rake_task'
6
+
7
+ Rspec::Core::RakeTask.new(:spec)
8
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ module Rails2ext
2
+ require 'active_support/all'
3
+ require 'active_record'
4
+ %w[active_support active_record].each do |filename|
5
+ require File.expand_path "../rails2ext/#{filename}", __FILE__
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), 'active_record/first_or_create')
2
+
3
+ ActiveRecord::Base.extend FirstOrCreate
@@ -0,0 +1,5 @@
1
+ module FirstOrCreate
2
+ def first_or_create!(args)
3
+ find(:first, :conditions => args) || new(args).tap {|record| record.save! }
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveSupport
2
+ require File.join(File.dirname(__FILE__), 'active_support/core_ext')
3
+ require File.join(File.dirname(__FILE__), 'active_support/command_retry')
4
+ require File.join(File.dirname(__FILE__), 'active_support/quick_logger')
5
+ end
@@ -0,0 +1,80 @@
1
+ # CommandRetry helps you repeat system commands when they
2
+ # are not successful for a given number of times (repeat
3
+ # once by default).
4
+ # If all repetitions fail, an error (default is
5
+ # RuntimeError) will be raised unless you passed in
6
+ # +:fail => false+ option
7
+ #
8
+ # It accepts also a +on+ option, which can be a single
9
+ # exit code or an array of exit codes that will cause
10
+ # the block to be repeated.
11
+ # Other exit codes not included in the +on+ array (if
12
+ # provided) will not cause repetitions and will will
13
+ # not raise errors.
14
+ #
15
+ # Will retry 5 times, failing each time and eventually
16
+ # raise the default error:
17
+ #
18
+ # CommandRetry.retry(:times => 5) { system 'bingobongo' }
19
+ # #=> RuntimeError: #<RuntimeError:0x101d89648>
20
+ #
21
+ # Will fail 5 times with exit code 7, eventually will
22
+ # raise custom error:
23
+ #
24
+ # CommandRetry.retry(:fail => ArgumentError, :on => 7 :times => 5) do
25
+ # system 'curl localhost:123/notfound'
26
+ # end
27
+ #
28
+ # Will fail just once since exit code 7 is not
29
+ # included in +on+ array, and will raise no error:
30
+ #
31
+ # CommandRetry.retry(:on => 52, :times => 5) do
32
+ # system 'curl localhost:123/notfound'
33
+ # end
34
+
35
+ class CommandRetry
36
+ def self.retry(opts={}, &block)
37
+ new(opts, &block).retry
38
+ end
39
+
40
+ def initialize(opts={}, &block)
41
+ opts.symbolize_keys!
42
+ @times = opts[:times] || 2
43
+ @fail = opts[:fail] || RuntimeError unless opts[:fail] == false
44
+ @on = Array.wrap(opts[:on]) if opts[:on]
45
+ @command = block
46
+ end
47
+
48
+ def retry
49
+ result = false
50
+ status = 0
51
+ @times.times do
52
+ result = @command.call
53
+ status = exit_status
54
+ if should_break?(status)
55
+ break
56
+ end
57
+ end
58
+
59
+ if @fail && status != 0
60
+ unless on_allows?(status)
61
+ raise @fail, caller
62
+ end
63
+ end
64
+ result
65
+ end
66
+
67
+ private
68
+
69
+ def exit_status
70
+ $?.exitstatus
71
+ end
72
+
73
+ def should_break?(status)
74
+ status.zero? or on_allows?(status)
75
+ end
76
+
77
+ def on_allows?(status)
78
+ @on && !@on.include?(status)
79
+ end
80
+ end
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].each { |filename| require filename }
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'array', 'uniq_by')
@@ -0,0 +1,11 @@
1
+ class Array
2
+ # Returns an unique array based on the criteria given as a +Proc+.
3
+ #
4
+ # [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2]
5
+ #
6
+ def uniq_by
7
+ hash, array = {}, []
8
+ each { |i| hash[yield(i)] ||= (array << i) }
9
+ array
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ class MissingSourceFile
2
+ REGEXPS << [/^cannot load such file -- (.+)$/i, 1]
3
+ end
4
+
@@ -0,0 +1,32 @@
1
+ require 'logger'
2
+
3
+ # quick and dirty logger: just inherit from here,
4
+ # set the filename attribute then you're ready to go
5
+ class QuickLogger
6
+ class << self
7
+ attr_accessor :filename
8
+
9
+ def filename_path
10
+ if defined?(Rails)
11
+ File.join Rails.root, 'log', [@filename, Rails.env, 'log'].join('.')
12
+ else
13
+ [@filename, 'log'].join('.')
14
+ end
15
+ end
16
+
17
+ def method_missing(log_level, message)
18
+ @logger ||= ::Logger.new(filename_path)
19
+ if ::Logger::SEV_LABEL.include?(log_level.to_s.upcase)
20
+ @logger.send log_level, "[#{Time.now}] #{message}"
21
+ else
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # keep legacy interface
29
+ module Quick
30
+ class Logger < QuickLogger
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Rails2ext
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rails2ext/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rails2ext"
7
+ s.version = Rails2ext::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["andrea longhi"]
10
+ s.email = ["andrea@spaghetticode.it"]
11
+ s.homepage = ""
12
+ s.summary = %q{some useful extensions for rails 2 apps}
13
+ s.description = %q{some useful extensions for rails 2 apps}
14
+
15
+ # s.rubyforge_project = "rails2ext"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency 'rails', '~> 2.3.0'
23
+ s.add_development_dependency 'rake'
24
+ s.add_development_dependency 'rspec'
25
+ s.add_development_dependency 'mocha'
26
+ s.add_development_dependency 'sqlite3'
27
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ class Person < ActiveRecord::Base
4
+ establish_connection :adapter => 'sqlite3', :database => ':memory:'
5
+ connection.create_table table_name, :force => true do |t|
6
+ t.string :name
7
+ end
8
+ end
9
+
10
+ describe FirstOrCreate do
11
+ before { Person.delete_all }
12
+
13
+ context 'when no record matches given attributes' do
14
+ context 'when attributes are valid' do
15
+ let(:attributes) { {:name => 'Joe'} }
16
+
17
+ it 'should create a new record' do
18
+ expect do
19
+ Person.first_or_create!(attributes)
20
+ end.to change(Person, :count).by(1)
21
+ end
22
+
23
+ it 'created record should have requested attributes' do
24
+ Person.first_or_create!(attributes)
25
+ Person.find_by_name(attributes[:name]).should_not be_nil
26
+ end
27
+ end
28
+
29
+ context 'when attributes are not valid' do
30
+ let(:attributes) { {:surname => 'Doe'} }
31
+
32
+ it 'should raise an error' do
33
+ expect do
34
+ Person.first_or_create!(attributes)
35
+ end.to raise_error(ActiveRecord::StatementInvalid)
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when a record matches given attributes' do
41
+ before do
42
+ @attributes = {:name => 'Joe'}
43
+ @joe = Person.create!(@attributes)
44
+ end
45
+
46
+ it 'should return that record' do
47
+ Person.first_or_create!(@attributes).should == @joe
48
+ end
49
+
50
+ it 'should not create a new record' do
51
+ expect do
52
+ Person.first_or_create!(@attributes)
53
+ end.to_not change(Person, :count)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe CommandRetry do
4
+ describe '#retry' do
5
+ context 'when command is successful' do
6
+ it 'should raise no error' do
7
+ command = CommandRetry.new {system 'echo'}
8
+ lambda {command.retry}.should_not raise_error
9
+ end
10
+ end
11
+
12
+ context 'when command is not successful' do
13
+ it 'should raise an error' do
14
+ command = CommandRetry.new {system 'will fail'}
15
+ lambda {command.retry}.should raise_error(RuntimeError)
16
+ end
17
+
18
+ context 'when providing "times" option' do
19
+ subject { CommandRetry.new(:times => 5) {system 'will fail'} }
20
+
21
+ it 'should repeat operation, if not successful' do
22
+ subject.expects(:exit_status).times(5).returns(1)
23
+ subject.retry rescue nil
24
+ end
25
+ end
26
+
27
+ context 'when providing "fail" option' do
28
+ context 'when "fail" is a class' do
29
+ subject { CommandRetry.new(:fail => ArgumentError) {system 'will fail'} }
30
+
31
+ it 'should raise expected error' do
32
+ lambda {subject.retry}.should raise_error(ArgumentError)
33
+ end
34
+ end
35
+
36
+ context 'when "fail" is set to false' do
37
+ subject { CommandRetry.new(:fail => false) {system 'will fail'} }
38
+
39
+ it 'should raise no error' do
40
+ lambda {subject.retry}.should_not raise_error
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'when providing "on" option' do
46
+ subject { CommandRetry.new(:on => 42, :times => 3) {system 'will fail'} }
47
+
48
+ it 'should retry for given exit codes' do
49
+ subject.expects(:exit_status).times(3).returns(42)
50
+ subject.retry rescue nil
51
+ end
52
+
53
+ it 'should not raise error for other exit codes' do
54
+ subject.expects(:exit_status).times(1).returns(1)
55
+ lambda {subject.retry}.should_not raise_error
56
+ end
57
+
58
+ it 'should not retry for other exit codes' do
59
+ subject.expects(:exit_status).times(1).returns(1)
60
+ subject.retry
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '::retry' do
67
+ it 'should wrap initialization and retry process' do
68
+ CommandRetry.any_instance.expects(:retry)
69
+ CommandRetry.retry(:fail => false) {system 'ls'}
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+ describe '#uniq_by' do
5
+ it 'should return an array' do
6
+ [].uniq_by {}.should be_an(Array)
7
+ end
8
+
9
+ it 'should return unique values' do
10
+ [1, 2, 3, 4].uniq_by { |i| i.odd? }.should == [1, 2]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ describe MissingSourceFile do
2
+ describe 'REGEXPS' do
3
+ it { MissingSourceFile::REGEXPS.should include([/^cannot load such file -- (.+)$/i, 1]) }
4
+ end
5
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe QuickLogger do
4
+ class TestLogger < QuickLogger; end
5
+
6
+ it 'should have filename accessor' do
7
+ filename = 'something_else'
8
+ TestLogger.filename = filename
9
+ TestLogger.filename.should == filename
10
+ end
11
+
12
+ describe 'filename_path' do
13
+ context 'when extending a rails app' do
14
+ before do
15
+ unless defined?(Rails)
16
+ module Rails; end
17
+ end
18
+ Rails.stubs(:env => 'test', :root => '/rails/rootpath')
19
+ end
20
+
21
+ it 'should be in log dir, include rails env, have log extension' do
22
+ TestLogger.filename = 'some/path'
23
+ TestLogger.filename_path.should == '/rails/rootpath/log/some/path.test.log'
24
+ end
25
+ end
26
+
27
+ context 'when used alone' do
28
+ before do
29
+ Object.send(:remove_const, :Rails) if defined?(Rails)
30
+ end
31
+
32
+ it 'should match the plain filename' do
33
+ TestLogger.filename = 'other/path'
34
+ TestLogger.filename_path.should == 'other/path.log'
35
+ end
36
+ end
37
+ end
38
+
39
+ it 'should respond to classic logger methods' do
40
+ lambda do
41
+ TestLogger.info "message"
42
+ end.should_not raise_error(NameError)
43
+ end
44
+ end
@@ -0,0 +1,6 @@
1
+ require 'mocha'
2
+ require 'rails2ext'
3
+
4
+ Spec::Runner.configure do |config|
5
+ config.mock_with :mocha
6
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails2ext
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - andrea longhi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-07-11 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 2
30
+ - 3
31
+ - 0
32
+ version: 2.3.0
33
+ type: :runtime
34
+ requirement: *id001
35
+ prerelease: false
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ requirement: *id002
49
+ prerelease: false
50
+ - !ruby/object:Gem::Dependency
51
+ name: rspec
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ requirement: *id003
63
+ prerelease: false
64
+ - !ruby/object:Gem::Dependency
65
+ name: mocha
66
+ version_requirements: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ requirement: *id004
77
+ prerelease: false
78
+ - !ruby/object:Gem::Dependency
79
+ name: sqlite3
80
+ version_requirements: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :development
90
+ requirement: *id005
91
+ prerelease: false
92
+ description: some useful extensions for rails 2 apps
93
+ email:
94
+ - andrea@spaghetticode.it
95
+ executables: []
96
+
97
+ extensions: []
98
+
99
+ extra_rdoc_files: []
100
+
101
+ files:
102
+ - .gitignore
103
+ - .rspec
104
+ - CHANGELOG
105
+ - Gemfile
106
+ - README.md
107
+ - Rakefile
108
+ - lib/rails2ext.rb
109
+ - lib/rails2ext/active_record.rb
110
+ - lib/rails2ext/active_record/first_or_create.rb
111
+ - lib/rails2ext/active_support.rb
112
+ - lib/rails2ext/active_support/command_retry.rb
113
+ - lib/rails2ext/active_support/core_ext.rb
114
+ - lib/rails2ext/active_support/core_ext/array.rb
115
+ - lib/rails2ext/active_support/core_ext/array/uniq_by.rb
116
+ - lib/rails2ext/active_support/core_ext/load_error.rb
117
+ - lib/rails2ext/active_support/quick_logger.rb
118
+ - lib/rails2ext/version.rb
119
+ - rails2ext.gemspec
120
+ - spec/active_record/first_or_create_spec.rb
121
+ - spec/active_support/command_retry_spec.rb
122
+ - spec/active_support/core_ext/array/uniq_by_spec.rb
123
+ - spec/active_support/core_ext/load_error_spec.rb
124
+ - spec/active_support/quick_logger_spec.rb
125
+ - spec/spec_helper.rb
126
+ homepage: ""
127
+ licenses: []
128
+
129
+ post_install_message:
130
+ rdoc_options: []
131
+
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ hash: 3
140
+ segments:
141
+ - 0
142
+ version: "0"
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ hash: 3
149
+ segments:
150
+ - 0
151
+ version: "0"
152
+ requirements: []
153
+
154
+ rubyforge_project:
155
+ rubygems_version: 1.8.24
156
+ signing_key:
157
+ specification_version: 3
158
+ summary: some useful extensions for rails 2 apps
159
+ test_files:
160
+ - spec/active_record/first_or_create_spec.rb
161
+ - spec/active_support/command_retry_spec.rb
162
+ - spec/active_support/core_ext/array/uniq_by_spec.rb
163
+ - spec/active_support/core_ext/load_error_spec.rb
164
+ - spec/active_support/quick_logger_spec.rb
165
+ - spec/spec_helper.rb