streamit 0.0.0 → 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 (42) hide show
  1. data/test/dummy/app/controllers/application_controller.rb +3 -0
  2. data/test/dummy/app/controllers/users_controller.rb +83 -0
  3. data/test/dummy/app/models/stream.rb +3 -0
  4. data/test/dummy/app/models/user.rb +7 -0
  5. data/test/dummy/app/views/layouts/application.html.erb +20 -0
  6. data/test/dummy/app/views/streamit/streams/_stream.html.erb +3 -0
  7. data/test/dummy/app/views/users/_form.html.erb +25 -0
  8. data/test/dummy/app/views/users/edit.html.erb +6 -0
  9. data/test/dummy/app/views/users/index.html.erb +25 -0
  10. data/test/dummy/app/views/users/new.html.erb +5 -0
  11. data/test/dummy/app/views/users/show.html.erb +15 -0
  12. data/test/dummy/config/application.rb +48 -0
  13. data/test/dummy/config/boot.rb +10 -0
  14. data/test/dummy/config/database.yml +22 -0
  15. data/test/dummy/config/environment.rb +5 -0
  16. data/test/dummy/config/environments/development.rb +26 -0
  17. data/test/dummy/config/environments/production.rb +49 -0
  18. data/test/dummy/config/environments/test.rb +35 -0
  19. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  20. data/test/dummy/config/initializers/secret_token.rb +7 -0
  21. data/test/dummy/config/initializers/session_store.rb +8 -0
  22. data/test/dummy/config/locales/en.yml +10 -0
  23. data/test/dummy/config/routes.rb +66 -0
  24. data/test/dummy/db/migrate/20110204210910_create_items.rb +13 -0
  25. data/test/dummy/db/migrate/20110204210955_create_users.rb +14 -0
  26. data/test/dummy/db/migrate/20110204211021_create_watchings.rb +14 -0
  27. data/test/dummy/db/migrate/20110206230646_create_streams.rb +18 -0
  28. data/test/dummy/public/javascripts/application.js +2 -0
  29. data/test/dummy/public/javascripts/controls.js +965 -0
  30. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  31. data/test/dummy/public/javascripts/effects.js +1123 -0
  32. data/test/dummy/public/javascripts/prototype.js +6001 -0
  33. data/test/dummy/public/javascripts/rails.js +175 -0
  34. data/test/dummy/public/stylesheets/scaffold.css +56 -0
  35. data/test/dummy/script/rails +6 -0
  36. data/test/integration/navigation_test.rb +36 -0
  37. data/test/store_test.rb +36 -0
  38. data/test/streamit_test.rb +118 -0
  39. data/test/support/fixtures.rb +14 -0
  40. data/test/support/integration_case.rb +5 -0
  41. data/test/test_helper.rb +22 -0
  42. metadata +89 -9
@@ -0,0 +1,175 @@
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
+ })();
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
@@ -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,36 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActiveSupport::IntegrationCase
4
+
5
+ def register_new_user
6
+ visit "/users/new"
7
+ fill_in "Name", :with => "davis"
8
+ click_button "Create User"
9
+ end
10
+
11
+ should "fetch recent streams" do
12
+ register_new_user
13
+ register_new_user
14
+ visit "/streamit/fetch"
15
+ assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
16
+ end
17
+
18
+ should "fetch streams in last ? seconds" do
19
+ Timecop.freeze(Time.now - 30.seconds) do
20
+ register_new_user
21
+ end
22
+ register_new_user
23
+ register_new_user
24
+ visit "/streamit/fetch?ago=30"
25
+ assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
26
+ end
27
+
28
+ should "fetch streams from after an id" do
29
+ register_new_user
30
+ register_new_user
31
+ register_new_user
32
+ visit "/streamit/fetch?after=#{Stream.last.id}"
33
+ assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
34
+ end
35
+
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class StoreTest < ActiveSupport::TestCase
4
+ setup do
5
+ @user = TestUser.create(:name => 'davis')
6
+ end
7
+
8
+ def default_args
9
+ { :stream_type => 'streamit.example',
10
+ :actor => @user,
11
+ :receiver => @user,
12
+ :subject => @user,
13
+ :started_at => Time.now }
14
+ end
15
+
16
+ def store!(args=default_args)
17
+ stream = Stream.new(args)
18
+ end
19
+
20
+ should "set the type" do
21
+ assert_equal "streamit.example", store!.stream_type
22
+ end
23
+
24
+ should "set started at" do
25
+ assert_kind_of Time, store!.started_at
26
+ end
27
+
28
+ should "translate type to meaningful words" do
29
+ I18n.backend.store_translations :en,
30
+ :streamit => { :example => "just an example" }
31
+
32
+ assert_equal "just an example", store!.stream_type_in_words
33
+ I18n.reload!
34
+ end
35
+
36
+ end
@@ -0,0 +1,118 @@
1
+ require 'test_helper'
2
+
3
+ class StreamitTest < ActiveSupport::TestCase
4
+ def stream_store
5
+ Streamit.store
6
+ end
7
+
8
+ context "when user watches an item" do
9
+ setup do
10
+ TestWatching.class_eval do
11
+ stream :create, :actor => :watcher, :subject => :watched_item
12
+ end
13
+ @watch = TestWatching.new(:watcher => TestUser.create!, :watched_item => TestItem.create!)
14
+ end
15
+
16
+ should "create a stream if watching is created successfully" do
17
+ @watch.save
18
+ stream = stream_store.last
19
+ assert_not_nil stream
20
+ assert_equal "streamit.testwatchings.create", stream.stream_type
21
+ assert_equal @watch.watcher, stream.actor
22
+ assert_equal @watch.watched_item, stream.subject
23
+ assert_nil stream.receiver
24
+ end
25
+
26
+ should "not create a stream if failed to create a watching" do
27
+ TestWatching.class_eval do
28
+ before_create { return false }
29
+ end
30
+ assert_no_difference("stream_store.count") { @watch.save }
31
+ end
32
+ end
33
+
34
+ context "when create or update a user" do
35
+ setup do
36
+ @user = TestUser.new
37
+ @user.singleton_class.class_eval do
38
+ def self.name; "TestUser"; end
39
+ end
40
+ end
41
+
42
+ should "create a stream" do
43
+ @user.singleton_class.class_eval do
44
+ stream :create
45
+ end
46
+ @user.save
47
+ stream = stream_store.last
48
+ assert_not_nil stream
49
+ assert_equal "streamit.testusers.create", stream.stream_type
50
+ assert_equal @user, stream.actor
51
+ assert_nil stream.subject
52
+ assert_nil stream.receiver
53
+ end
54
+
55
+ context "when user updates her attributes" do
56
+ setup do
57
+ @user.save
58
+ end
59
+
60
+ should "create a stream the attribute specified has changed" do
61
+ @user.singleton_class.class_eval do
62
+ stream :update, :attributes => :image_url
63
+ end
64
+ @user.image_url = "image"
65
+ @user.save
66
+ stream = stream_store.last
67
+ assert_not_nil stream
68
+ assert_equal "streamit.testusers.update.image_url", stream.stream_type
69
+ assert_equal @user, stream.actor
70
+ assert_nil stream.subject
71
+ assert_nil stream.receiver
72
+ end
73
+
74
+ should "create a stream if any attributes have changed" do
75
+ @user.singleton_class.class_eval do
76
+ stream :update
77
+ end
78
+ @user.name = "davis"
79
+ @user.save
80
+ stream = stream_store.last
81
+ assert_not_nil stream
82
+ assert_equal "streamit.testusers.update.default", stream.stream_type
83
+ assert_equal @user, stream.actor
84
+ assert_nil stream.subject
85
+ assert_nil stream.receiver
86
+ end
87
+
88
+ should "create a stream if any attributes specified have changed" do
89
+ @user.singleton_class.class_eval do
90
+ stream :update, :attributes => [:name, :image_url]
91
+ end
92
+ @user.name = "davis"
93
+ @user.save
94
+ stream = stream_store.last
95
+ assert_not_nil stream
96
+ assert_equal "streamit.testusers.update.default", stream.stream_type
97
+ assert_equal @user, stream.actor
98
+ assert_nil stream.subject
99
+ assert_nil stream.receiver
100
+ end
101
+
102
+ should "not create a stream if no attributes has changed" do
103
+ assert_no_difference("stream_store.count") { @user.save }
104
+ end
105
+
106
+ should "not create a stream if no attributes specified has changed" do
107
+ @user.singleton_class.class_eval do
108
+ stream :update, :attributes => :name
109
+ end
110
+ @user.image_url = "image"
111
+ @user.save
112
+ assert_equal 0, stream_store.count
113
+ end
114
+ end
115
+ end
116
+
117
+ end
118
+
@@ -0,0 +1,14 @@
1
+ class TestUser < ActiveRecord::Base
2
+ self.table_name = "users"
3
+ end
4
+
5
+ class TestItem < ActiveRecord::Base
6
+ self.table_name = "items"
7
+ end
8
+
9
+ class TestWatching < ActiveRecord::Base
10
+ self.table_name = "watchings"
11
+
12
+ belongs_to :watcher, :class_name => "TestUser", :foreign_key => "user_id"
13
+ belongs_to :watched_item, :class_name => "TestItem", :foreign_key => "item_id"
14
+ end