trackable_tasks 0.0.1

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 (65) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG +7 -0
  4. data/Gemfile +22 -0
  5. data/Gemfile.lock +159 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +77 -0
  8. data/Rakefile +90 -0
  9. data/VERSION +1 -0
  10. data/app/models/trackable_tasks/task_run.rb +39 -0
  11. data/config/routes.rb +0 -0
  12. data/lib/generators/trackable_tasks/install_generator.rb +43 -0
  13. data/lib/generators/trackable_tasks/templates/migrations/install_migration.rb.erb +16 -0
  14. data/lib/generators/trackable_tasks/templates/trackable_tasks.rake +48 -0
  15. data/lib/trackable_tasks/base.rb +87 -0
  16. data/lib/trackable_tasks/config.rb +0 -0
  17. data/lib/trackable_tasks/engine.rb +7 -0
  18. data/lib/trackable_tasks/railtie.rb +11 -0
  19. data/lib/trackable_tasks.rb +5 -0
  20. data/spec/dummy/Rakefile +7 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  22. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  23. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  24. data/spec/dummy/config/application.rb +45 -0
  25. data/spec/dummy/config/boot.rb +10 -0
  26. data/spec/dummy/config/database.yml +22 -0
  27. data/spec/dummy/config/environment.rb +5 -0
  28. data/spec/dummy/config/environments/development.rb +26 -0
  29. data/spec/dummy/config/environments/production.rb +49 -0
  30. data/spec/dummy/config/environments/test.rb +35 -0
  31. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  32. data/spec/dummy/config/initializers/inflections.rb +10 -0
  33. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  34. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  35. data/spec/dummy/config/initializers/session_store.rb +8 -0
  36. data/spec/dummy/config/locales/en.yml +5 -0
  37. data/spec/dummy/config/routes.rb +58 -0
  38. data/spec/dummy/config.ru +4 -0
  39. data/spec/dummy/db/migrate/20110826183240_create_trackable_task_tables.rb +16 -0
  40. data/spec/dummy/db/schema.rb +24 -0
  41. data/spec/dummy/features/step_definitions/trackable_tasks_steps.rb +0 -0
  42. data/spec/dummy/features/support/env.rb +15 -0
  43. data/spec/dummy/lib/tasks/trackable_tasks.rake +48 -0
  44. data/spec/dummy/lib/trackable_tasks/my_task.rb +8 -0
  45. data/spec/dummy/public/404.html +26 -0
  46. data/spec/dummy/public/422.html +26 -0
  47. data/spec/dummy/public/500.html +26 -0
  48. data/spec/dummy/public/favicon.ico +0 -0
  49. data/spec/dummy/public/javascripts/application.js +2 -0
  50. data/spec/dummy/public/javascripts/controls.js +965 -0
  51. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  52. data/spec/dummy/public/javascripts/effects.js +1123 -0
  53. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  54. data/spec/dummy/public/javascripts/rails.js +191 -0
  55. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  56. data/spec/dummy/script/rails +6 -0
  57. data/spec/integration/navigation_spec.rb +9 -0
  58. data/spec/models/task_run_spec.rb +100 -0
  59. data/spec/rake_task_spec.rb +29 -0
  60. data/spec/spec_helper.rb +37 -0
  61. data/spec/support/sample_tasks.rb +26 -0
  62. data/spec/trackable_task_base_spec.rb +168 -0
  63. data/spec/trackable_tasks_spec.rb +7 -0
  64. data/trackable_tasks.gemspec +145 -0
  65. metadata +285 -0
@@ -0,0 +1,191 @@
1
+ (function() {
2
+ // Technique from Juriy Zaytsev
3
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
+ function isEventSupported(eventName) {
5
+ var el = document.createElement('div');
6
+ eventName = 'on' + eventName;
7
+ var isSupported = (eventName in el);
8
+ if (!isSupported) {
9
+ el.setAttribute(eventName, 'return;');
10
+ isSupported = typeof el[eventName] == 'function';
11
+ }
12
+ el = null;
13
+ return isSupported;
14
+ }
15
+
16
+ function isForm(element) {
17
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
+ }
19
+
20
+ function isInput(element) {
21
+ if (Object.isElement(element)) {
22
+ var name = element.nodeName.toUpperCase()
23
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
+ }
25
+ else return false
26
+ }
27
+
28
+ var submitBubbles = isEventSupported('submit'),
29
+ changeBubbles = isEventSupported('change')
30
+
31
+ if (!submitBubbles || !changeBubbles) {
32
+ // augment the Event.Handler class to observe custom events when needed
33
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
+ function(init, element, eventName, selector, callback) {
35
+ init(element, eventName, selector, callback)
36
+ // is the handler being attached to an element that doesn't support this event?
37
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
+ // "submit" => "emulated:submit"
40
+ this.eventName = 'emulated:' + this.eventName
41
+ }
42
+ }
43
+ )
44
+ }
45
+
46
+ if (!submitBubbles) {
47
+ // discover forms on the page by observing focus events which always bubble
48
+ document.on('focusin', 'form', function(focusEvent, form) {
49
+ // special handler for the real "submit" event (one-time operation)
50
+ if (!form.retrieve('emulated:submit')) {
51
+ form.on('submit', function(submitEvent) {
52
+ var emulated = form.fire('emulated:submit', submitEvent, true)
53
+ // if custom event received preventDefault, cancel the real one too
54
+ if (emulated.returnValue === false) submitEvent.preventDefault()
55
+ })
56
+ form.store('emulated:submit', true)
57
+ }
58
+ })
59
+ }
60
+
61
+ if (!changeBubbles) {
62
+ // discover form inputs on the page
63
+ document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
+ // special handler for real "change" events
65
+ if (!input.retrieve('emulated:change')) {
66
+ input.on('change', function(changeEvent) {
67
+ input.fire('emulated:change', changeEvent, true)
68
+ })
69
+ input.store('emulated:change', true)
70
+ }
71
+ })
72
+ }
73
+
74
+ function handleRemote(element) {
75
+ var method, url, params;
76
+
77
+ var event = element.fire("ajax:before");
78
+ if (event.stopped) return false;
79
+
80
+ if (element.tagName.toLowerCase() === 'form') {
81
+ method = element.readAttribute('method') || 'post';
82
+ url = element.readAttribute('action');
83
+ params = element.serialize();
84
+ } else {
85
+ method = element.readAttribute('data-method') || 'get';
86
+ url = element.readAttribute('href');
87
+ params = {};
88
+ }
89
+
90
+ new Ajax.Request(url, {
91
+ method: method,
92
+ parameters: params,
93
+ evalScripts: true,
94
+
95
+ onComplete: function(request) { element.fire("ajax:complete", request); },
96
+ onSuccess: function(request) { element.fire("ajax:success", request); },
97
+ onFailure: function(request) { element.fire("ajax:failure", request); }
98
+ });
99
+
100
+ element.fire("ajax:after");
101
+ }
102
+
103
+ function handleMethod(element) {
104
+ var method = element.readAttribute('data-method'),
105
+ url = element.readAttribute('href'),
106
+ csrf_param = $$('meta[name=csrf-param]')[0],
107
+ csrf_token = $$('meta[name=csrf-token]')[0];
108
+
109
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
+ element.parentNode.insert(form);
111
+
112
+ if (method !== 'post') {
113
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
+ form.insert(field);
115
+ }
116
+
117
+ if (csrf_param) {
118
+ var param = csrf_param.readAttribute('content'),
119
+ token = csrf_token.readAttribute('content'),
120
+ field = new Element('input', { type: 'hidden', name: param, value: token });
121
+ form.insert(field);
122
+ }
123
+
124
+ form.submit();
125
+ }
126
+
127
+
128
+ document.on("click", "*[data-confirm]", function(event, element) {
129
+ var message = element.readAttribute('data-confirm');
130
+ if (!confirm(message)) event.stop();
131
+ });
132
+
133
+ document.on("click", "a[data-remote]", function(event, element) {
134
+ if (event.stopped) return;
135
+ handleRemote(element);
136
+ event.stop();
137
+ });
138
+
139
+ document.on("click", "a[data-method]", function(event, element) {
140
+ if (event.stopped) return;
141
+ handleMethod(element);
142
+ event.stop();
143
+ });
144
+
145
+ document.on("submit", function(event) {
146
+ var element = event.findElement(),
147
+ message = element.readAttribute('data-confirm');
148
+ if (message && !confirm(message)) {
149
+ event.stop();
150
+ return false;
151
+ }
152
+
153
+ var inputs = element.select("input[type=submit][data-disable-with]");
154
+ inputs.each(function(input) {
155
+ input.disabled = true;
156
+ input.writeAttribute('data-original-value', input.value);
157
+ input.value = input.readAttribute('data-disable-with');
158
+ });
159
+
160
+ var element = event.findElement("form[data-remote]");
161
+ if (element) {
162
+ handleRemote(element);
163
+ event.stop();
164
+ }
165
+ });
166
+
167
+ document.on("ajax:after", "form", function(event, element) {
168
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
+ inputs.each(function(input) {
170
+ input.value = input.readAttribute('data-original-value');
171
+ input.removeAttribute('data-original-value');
172
+ input.disabled = false;
173
+ });
174
+ });
175
+
176
+ Ajax.Responders.register({
177
+ onCreate: function(request) {
178
+ var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
179
+
180
+ if (csrf_meta_tag) {
181
+ var header = 'X-CSRF-Token',
182
+ token = csrf_meta_tag.readAttribute('content');
183
+
184
+ if (!request.options.requestHeaders) {
185
+ request.options.requestHeaders = {};
186
+ }
187
+ request.options.requestHeaders[header] = token;
188
+ }
189
+ }
190
+ });
191
+ })();
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Navigation" do
4
+ include Capybara
5
+
6
+ it "should be a valid app" do
7
+ ::Rails.application.should be_a(Dummy::Application)
8
+ end
9
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ include TrackableTasks
3
+
4
+ describe TaskRun do
5
+ describe "validations" do
6
+ before(:each) do
7
+ @valid_attributes = {
8
+ :start_time => Time.now,
9
+ :task_type => "my_task",
10
+ :success => false
11
+ }
12
+ @run = TaskRun.new()
13
+ end
14
+
15
+ it "should be valid" do
16
+ @run.attributes = @valid_attributes
17
+ @run.should be_valid
18
+ end
19
+
20
+ it "should require task type" do
21
+ @run.should have(1).error_on(:task_type)
22
+ end
23
+
24
+ it "should require start time" do
25
+ @run.should have(1).error_on(:start_time)
26
+ end
27
+
28
+ it "should require success" do
29
+ @run.success = nil
30
+ @run.should have(1).error_on(:success)
31
+ end
32
+
33
+ it "should default to success = false" do
34
+ @run.success.should == false
35
+ @run.should have(0).error_on(:success)
36
+ end
37
+
38
+ it "end time should be after start time" do
39
+ end
40
+ end
41
+
42
+ describe "add_log_text method" do
43
+ before(:each) do
44
+ @run = TaskRun.new()
45
+ @text = "This trackable task is cool"
46
+ end
47
+
48
+ it "should take one parameter" do
49
+ @run.method(:add_log_text).arity.should == 1
50
+ end
51
+
52
+ it "should add a newline after the input text" do
53
+ @run.add_log_text(@text)
54
+ @run.log_text.should == (@text + "\n")
55
+ end
56
+
57
+ it "should save the string to the log_text if it is empty" do
58
+ @run.add_log_text(@text)
59
+ @run.log_text.should match @text
60
+ end
61
+
62
+ it "should append the string to the text if it is not empty" do
63
+ original_text = "first log text"
64
+ @run.log_text = original_text
65
+ @run.add_log_text(@text)
66
+ @run.log_text.should match original_text
67
+ @run.log_text.should match @text
68
+ end
69
+
70
+ end
71
+
72
+ describe "add_error_text method" do
73
+ before(:each) do
74
+ @run = TaskRun.new()
75
+ @text = "This trackable task is erroring"
76
+ end
77
+
78
+ it "should take one parameter" do
79
+ @run.method(:add_error_text).arity.should == 1
80
+ end
81
+
82
+ it "should add a newline after the input text" do
83
+ @run.add_error_text(@text)
84
+ @run.error_text.should == (@text + "\n")
85
+ end
86
+
87
+ it "should save the string to the error_text if it is empty" do
88
+ @run.add_error_text(@text)
89
+ @run.error_text.should match @text
90
+ end
91
+
92
+ it "should append the string to the text if it is not empty" do
93
+ original_text = "first log text"
94
+ @run.error_text = original_text
95
+ @run.add_error_text(@text)
96
+ @run.error_text.should match original_text
97
+ @run.error_text.should match @text
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+ require "rake"
3
+
4
+ # only doing light testing of the rake tasks
5
+ # probably could increase coverage at some point but I can't figure out how to stub the run_trackable_task function
6
+ describe "trackable_task rake tasks" do
7
+ before(:each) do
8
+ @rake = Rake::Application.new
9
+ Rake.application = @rake
10
+ Rake.application.rake_require "dummy/lib/tasks/trackable_tasks"
11
+ Rake::Task.define_task(:environment)
12
+ end
13
+
14
+ describe "dynamic rake task" do
15
+ it "should load the file names in the lib/trackable_tasks folder" do
16
+ @task_name = "trackable_task:my_task"
17
+ @rake[@task_name].invoke
18
+ TrackableTasks::TaskRun.last.task_type.should == "MyTask"
19
+ end
20
+ end
21
+
22
+ describe "run rake task" do
23
+ before(:each) do
24
+ @task_name = "trackable_task:run task_name=my_task"
25
+ @rake[@task_name].invoke
26
+ TrackableTasks::TaskRun.last.task_type.should == "MyTask"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require "ruby-debug"
5
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
6
+ require "rails/test_help"
7
+ require "rspec/rails"
8
+
9
+ ActionMailer::Base.delivery_method = :test
10
+ ActionMailer::Base.perform_deliveries = true
11
+ ActionMailer::Base.default_url_options[:host] = "test.com"
12
+
13
+ Rails.backtrace_cleaner.remove_silencers!
14
+
15
+ # Configure capybara for integration testing
16
+ require "capybara/rails"
17
+ Capybara.default_driver = :rack_test
18
+ Capybara.default_selector = :css
19
+
20
+ # Run any available migration
21
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
22
+
23
+ # Load support files
24
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
25
+
26
+ RSpec.configure do |config|
27
+ # Remove this line if you don't want RSpec's should and should_not
28
+ # methods or matchers
29
+ require 'rspec/expectations'
30
+ config.include RSpec::Matchers
31
+
32
+ # == Mock Framework
33
+ config.mock_with :rspec
34
+
35
+ # use transactions
36
+ config.use_transactional_fixtures = true
37
+ end
@@ -0,0 +1,26 @@
1
+ class MyTask < TrackableTasks::Base
2
+
3
+ # convenience method to make our lives easier
4
+ # @task_run is not noramlly visible
5
+ def task_run
6
+ @task_run
7
+ end
8
+
9
+ def run
10
+ #log "Running MyTask"
11
+ end
12
+ end
13
+
14
+ class ErroringTask < TrackableTasks::Base
15
+
16
+ def error_text
17
+ "This task is supposed to error so here it is."
18
+ end
19
+
20
+ def run
21
+ raise error_text
22
+ end
23
+ end
24
+
25
+ class TaskWithoutRun < TrackableTasks::Base
26
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe TrackableTasks::Base do
4
+ describe "initialize method" do
5
+ before(:each) do
6
+ @mt = MyTask.new
7
+ end
8
+
9
+ it "should create a task run instance" do
10
+ TrackableTasks::TaskRun.all.length.should == 1
11
+ end
12
+
13
+ it "should set the start time" do
14
+ @mt.task_run.start_time.should_not be_nil
15
+ end
16
+
17
+ it "should set the type" do
18
+ @mt.task_run.task_type.should == "MyTask"
19
+ end
20
+
21
+ it "should be successful" do
22
+ # it should be successful on initialization
23
+ @mt.task_run.success.should be_true
24
+ end
25
+
26
+ it "should default to notice if no log level is set" do
27
+ # this awesome piece of code adds a method to @mt on the fly so I can
28
+ # access the log_level instance variable
29
+ # I am pretty sure this is the wrong way to do things
30
+ def @mt.log_level
31
+ @log_level
32
+ end
33
+ @mt.log_level.should == :notice
34
+ end
35
+ end
36
+
37
+ describe "allowable_log_level method" do
38
+ before(:each) do
39
+ @mt = MyTask.new
40
+ end
41
+
42
+ it "should change the log level to notice if not an allowable level" do
43
+ @mt.allowable_log_level(:illegal_level).should == :notice
44
+ end
45
+
46
+ it "should not change the level if it is allowable" do
47
+ @mt.allowable_log_level(:notice).should == :notice
48
+ end
49
+
50
+ it "should convert the input to a string before comparing if it is nil" do
51
+ @mt.allowable_log_level(nil).should == :notice
52
+ end
53
+
54
+ it "should convert the input to a symbol before comparing it against the allowable log levels" do
55
+ @mt.allowable_log_level("error").should == :error
56
+ end
57
+ end
58
+
59
+ describe "run_task" do
60
+ before(:each) do
61
+ @mt = MyTask.new
62
+ end
63
+
64
+ it "should call the run method" do
65
+ @mt.should_receive(:run)
66
+ @mt.run_task
67
+ end
68
+
69
+ it "should be successful if no errors were raised" do
70
+ @mt.run_task
71
+ @mt.task_run.success.should be_true
72
+ end
73
+
74
+ it "should handle errors from the run method by saving them to the error log" do
75
+ @erroring_task = ErroringTask.new
76
+ @erroring_task.run_task
77
+ @task_run = TrackableTasks::TaskRun.last
78
+ @task_run.error_text.should match ""
79
+ end
80
+
81
+ it "should not be successful if any errors were raised" do
82
+ @erroring_task = ErroringTask.new
83
+ @erroring_task.run_task
84
+ @task_run = TrackableTasks::TaskRun.last
85
+ @task_run.success.should be_false
86
+ end
87
+ end
88
+
89
+ describe "run method" do
90
+ it "should error if it isn't overriden" do
91
+ @t = TaskWithoutRun.new
92
+ @t.run_task
93
+ @task_run = TrackableTasks::TaskRun.last
94
+ @task_run.error_text.should match "The run method must be overridden"
95
+ @task_run.error_text.should match "NotImplementedError"
96
+ end
97
+ end
98
+
99
+ describe "log method" do
100
+ before(:each) do
101
+ @mt = MyTask.new
102
+ end
103
+
104
+ it "should take one argument" do
105
+ # I don't know why this is -2
106
+ # Maybe we should just remove this test
107
+ @mt.method(:log).arity.should == -2
108
+ end
109
+
110
+ it "should call the task run's add_log_text method" do
111
+ @mt.log("test log text")
112
+ @mt.run_task
113
+ @mt.task_run.log_text.should match "test log text"
114
+ end
115
+
116
+ it "should default to a log level of notice" do
117
+ @mt = MyTask.new(:error)
118
+ @mt.log("text that shouldn't be saved")
119
+ @mt.task_run.log_text.should be_nil
120
+ end
121
+
122
+ it "should call allowable_log_level" do
123
+ @mt.should_receive(:allowable_log_level).and_return(:notice)
124
+ @mt.log("some random text")
125
+ end
126
+
127
+ # test each of the three log levels to see if it saves at the correct time
128
+ it "should save debug logs if the log level is set to debug" do
129
+ # whether or not to save at each of the levels
130
+ levels = { :debug => true, :notice => false, :error => false }
131
+ levels.each_pair do |level, save|
132
+ @mt = MyTask.new(level)
133
+ @mt.log("some debugging text", :debug)
134
+ if save
135
+ @mt.task_run.log_text.should match "some debugging text"
136
+ else
137
+ @mt.task_run.log_text.should be_nil
138
+ end
139
+ end
140
+ end
141
+
142
+ it "should save notice logs if the log level is debug or notice" do
143
+ levels = { :debug => true, :notice => true, :error => false }
144
+ levels.each_pair do |level, save|
145
+ @mt = MyTask.new(level)
146
+ @mt.log("some debugging text", :notice)
147
+ if save
148
+ @mt.task_run.log_text.should match "some debugging text"
149
+ else
150
+ @mt.task_run.log_text.should be_nil
151
+ end
152
+ end
153
+ end
154
+
155
+ it "should save error logs to the task run's error log on any level" do
156
+ levels = { :debug => true, :notice => true, :error => true }
157
+ levels.each_pair do |level, save|
158
+ @mt = MyTask.new(level)
159
+ @mt.log("some debugging text", :error)
160
+ if save
161
+ @mt.task_run.error_text.should match "some debugging text"
162
+ else
163
+ @mt.task_run.error_text.should_not match "some debugging text"
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe TrackableTasks do
4
+ it "should be valid" do
5
+ TrackableTasks.should be_a(Module)
6
+ end
7
+ end