impressionist 1.0.1 → 1.1.0

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 (116) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.rdoc +1 -1
  5. data/Gemfile +8 -19
  6. data/README.md +65 -34
  7. data/Rakefile +10 -82
  8. data/app/controllers/impressionist_controller.rb +11 -11
  9. data/app/models/impression.rb +2 -15
  10. data/app/models/impressionist/bots.rb +3 -3
  11. data/app/models/impressionist/impressionable.rb +29 -41
  12. data/impressionist.gemspec +22 -65
  13. data/lib/generators/active_record/impressionist_generator.rb +21 -0
  14. data/lib/generators/{impressionist → active_record}/templates/create_impressions_table.rb +1 -9
  15. data/lib/generators/impressionist_generator.rb +12 -0
  16. data/lib/generators/mongo_mapper/impressionist_generator.rb +8 -0
  17. data/lib/generators/templates/impression.rb +5 -0
  18. data/lib/impressionist.rb +10 -3
  19. data/lib/impressionist/bots.rb +1 -1
  20. data/lib/impressionist/engine.rb +11 -3
  21. data/lib/impressionist/models/active_record/impression.rb +18 -0
  22. data/lib/impressionist/models/active_record/impressionist/impressionable.rb +12 -0
  23. data/lib/impressionist/models/mongo_mapper/impression.rb +17 -0
  24. data/lib/impressionist/models/mongo_mapper/impressionist/impressionable.rb +12 -0
  25. data/lib/impressionist/version.rb +3 -0
  26. data/test_app/.gitignore +17 -0
  27. data/test_app/.rspec +1 -0
  28. data/test_app/Gemfile +58 -0
  29. data/test_app/README +256 -0
  30. data/test_app/README.rdoc +261 -0
  31. data/test_app/Rakefile +7 -0
  32. data/test_app/app/assets/images/rails.png +0 -0
  33. data/test_app/app/assets/javascripts/application.js +15 -0
  34. data/test_app/app/assets/stylesheets/application.css +13 -0
  35. data/test_app/app/controllers/application_controller.rb +8 -0
  36. data/test_app/app/controllers/articles_controller.rb +18 -0
  37. data/test_app/app/controllers/dummy_controller.rb +6 -0
  38. data/test_app/app/controllers/posts_controller.rb +23 -0
  39. data/test_app/app/controllers/widgets_controller.rb +13 -0
  40. data/test_app/app/helpers/application_helper.rb +2 -0
  41. data/{lib/impressionist/railties/tasks.rake → test_app/app/mailers/.gitkeep} +0 -0
  42. data/test_app/app/models/.gitkeep +0 -0
  43. data/test_app/app/models/article.rb +3 -0
  44. data/test_app/app/models/dummy.rb +7 -0
  45. data/test_app/app/models/post.rb +3 -0
  46. data/test_app/app/models/user.rb +3 -0
  47. data/test_app/app/models/widget.rb +3 -0
  48. data/test_app/app/views/articles/index.html.erb +1 -0
  49. data/test_app/app/views/articles/show.html.erb +1 -0
  50. data/test_app/app/views/layouts/application.html.erb +14 -0
  51. data/test_app/app/views/posts/edit.html.erb +0 -0
  52. data/test_app/app/views/posts/index.html.erb +0 -0
  53. data/test_app/app/views/posts/show.html.erb +0 -0
  54. data/test_app/app/views/widgets/index.html.erb +0 -0
  55. data/test_app/app/views/widgets/new.html.erb +0 -0
  56. data/test_app/app/views/widgets/show.html.erb +0 -0
  57. data/test_app/config.ru +4 -0
  58. data/test_app/config/application.rb +59 -0
  59. data/test_app/config/boot.rb +6 -0
  60. data/test_app/config/cucumber.yml +8 -0
  61. data/test_app/config/database.yml +30 -0
  62. data/test_app/config/environment.rb +5 -0
  63. data/test_app/config/environments/development.rb +37 -0
  64. data/test_app/config/environments/pg_test.rb +35 -0
  65. data/test_app/config/environments/production.rb +67 -0
  66. data/test_app/config/environments/test.rb +37 -0
  67. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  68. data/test_app/config/initializers/impression.rb +5 -0
  69. data/test_app/config/initializers/inflections.rb +15 -0
  70. data/test_app/config/initializers/mime_types.rb +5 -0
  71. data/test_app/config/initializers/secret_token.rb +7 -0
  72. data/test_app/config/initializers/session_store.rb +8 -0
  73. data/test_app/config/initializers/wrap_parameters.rb +14 -0
  74. data/test_app/config/locales/en.yml +5 -0
  75. data/test_app/config/routes.rb +3 -0
  76. data/test_app/db/migrate/20110201153144_create_articles.rb +13 -0
  77. data/test_app/db/migrate/20110210205028_create_posts.rb +13 -0
  78. data/test_app/db/migrate/20111127184039_create_widgets.rb +15 -0
  79. data/test_app/db/seeds.rb +7 -0
  80. data/test_app/lib/assets/.gitkeep +0 -0
  81. data/test_app/lib/tasks/.gitkeep +0 -0
  82. data/test_app/lib/tasks/cucumber.rake +53 -0
  83. data/test_app/log/.gitkeep +0 -0
  84. data/test_app/public/404.html +26 -0
  85. data/test_app/public/422.html +26 -0
  86. data/test_app/public/500.html +25 -0
  87. data/test_app/public/favicon.ico +0 -0
  88. data/test_app/public/images/rails.png +0 -0
  89. data/test_app/public/index.html +241 -0
  90. data/test_app/public/javascripts/application.js +2 -0
  91. data/test_app/public/javascripts/controls.js +965 -0
  92. data/test_app/public/javascripts/dragdrop.js +974 -0
  93. data/test_app/public/javascripts/effects.js +1123 -0
  94. data/test_app/public/javascripts/prototype.js +6001 -0
  95. data/test_app/public/javascripts/rails.js +175 -0
  96. data/test_app/public/robots.txt +5 -0
  97. data/test_app/public/stylesheets/.gitkeep +0 -0
  98. data/test_app/script/cucumber +10 -0
  99. data/test_app/script/rails +6 -0
  100. data/test_app/spec/controllers/controller_spec.rb +125 -0
  101. data/test_app/spec/controllers/impressionist_uniqueness_spec.rb +310 -0
  102. data/test_app/spec/fixtures/articles.yml +3 -0
  103. data/test_app/spec/fixtures/impressions.yml +43 -0
  104. data/test_app/spec/fixtures/posts.yml +3 -0
  105. data/test_app/spec/fixtures/widgets.yml +4 -0
  106. data/test_app/spec/intializers/initializers_spec.rb +18 -0
  107. data/test_app/spec/models/counter_caching_spec.rb +30 -0
  108. data/test_app/spec/models/model_spec.rb +94 -0
  109. data/test_app/spec/rails_generators/rails_generators_spec.rb +23 -0
  110. data/test_app/spec/spec_helper.rb +36 -0
  111. data/upgrade_migrations/version_0_3_0.rb +7 -7
  112. data/upgrade_migrations/version_0_4_0.rb +2 -2
  113. metadata +356 -99
  114. data/VERSION +0 -1
  115. data/config/routes.rb +0 -2
  116. data/lib/generators/impressionist/impressionist_generator.rb +0 -20
@@ -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,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
File without changes
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4
+ if vendored_cucumber_bin
5
+ load File.expand_path(vendored_cucumber_bin)
6
+ else
7
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
8
+ require 'cucumber'
9
+ load Cucumber::BINARY
10
+ end
@@ -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,125 @@
1
+ require 'spec_helper'
2
+
3
+ describe ArticlesController do
4
+ fixtures :articles,:impressions,:posts,:widgets
5
+ render_views
6
+
7
+ it "should make the impressionable_hash available" do
8
+ get "index"
9
+ response.body.include?("false").should eq true
10
+ end
11
+
12
+ it "should log an impression with a message" do
13
+ get "index"
14
+ Impression.all.size.should eq 12
15
+ Article.first.impressions.last.message.should eq "this is a test article impression"
16
+ Article.first.impressions.last.controller_name.should eq "articles"
17
+ Article.first.impressions.last.action_name.should eq "index"
18
+ end
19
+
20
+ it "should log an impression without a message" do
21
+ get "show", :id=> 1
22
+ Impression.all.size.should eq 12
23
+ Article.first.impressions.last.message.should eq nil
24
+ Article.first.impressions.last.controller_name.should eq "articles"
25
+ Article.first.impressions.last.action_name.should eq "show"
26
+ end
27
+
28
+ it "should log the user_id if user is authenticated (@current_user before_filter method)" do
29
+ session[:user_id] = 123
30
+ get "show", :id=> 1
31
+ Article.first.impressions.last.user_id.should eq 123
32
+ end
33
+
34
+ it "should not log the user_id if user is authenticated" do
35
+ get "show", :id=> 1
36
+ Article.first.impressions.last.user_id.should eq nil
37
+ end
38
+
39
+ it "should log the request_hash, ip_address, referrer and session_hash" do
40
+ get "show", :id=> 1
41
+ Impression.last.request_hash.size.should eq 64
42
+ Impression.last.ip_address.should eq "0.0.0.0"
43
+ Impression.last.session_hash.size.should eq 32
44
+ Impression.last.referrer.should eq nil
45
+ end
46
+
47
+ it "should log the referrer when you click a link" do
48
+ visit article_url(Article.first)
49
+ click_link "Same Page"
50
+ Impression.last.referrer.should eq "http://test.host/articles/1"
51
+ end
52
+ end
53
+
54
+ describe PostsController do
55
+ it "should log impression at the action level" do
56
+ get "show", :id=> 1
57
+ Impression.all.size.should eq 12
58
+ Impression.last.controller_name.should eq "posts"
59
+ Impression.last.action_name.should eq "show"
60
+ Impression.last.impressionable_type.should eq "Post"
61
+ Impression.last.impressionable_id.should eq 1
62
+ end
63
+
64
+ it "should log the user_id if user is authenticated (current_user helper method)" do
65
+ session[:user_id] = 123
66
+ get "show", :id=> 1
67
+ Post.first.impressions.last.user_id.should eq 123
68
+ end
69
+ end
70
+
71
+ describe WidgetsController do
72
+
73
+ before(:each) do
74
+ @widget = Widget.find(1)
75
+ Widget.stub(:find).and_return(@widget)
76
+ end
77
+
78
+ it "should log impression at the per action level" do
79
+ get "show", :id=> 1
80
+ Impression.all.size.should eq 12
81
+ get "index"
82
+ Impression.all.size.should eq 13
83
+ get "new"
84
+ Impression.all.size.should eq 13
85
+ end
86
+
87
+ it "should not log impression when user-agent is in wildcard list" do
88
+ request.stub!(:user_agent).and_return('somebot')
89
+ get "show", :id=> 1
90
+ Impression.all.size.should eq 11
91
+ end
92
+
93
+ it "should not log impression when user-agent is in the bot list" do
94
+ request.stub!(:user_agent).and_return('Acoon Robot v1.50.001')
95
+ get "show", :id=> 1
96
+ Impression.all.size.should eq 11
97
+ end
98
+
99
+ describe "impressionist unique options" do
100
+
101
+ it "should log unique impressions at the per action level" do
102
+ get "show", :id=> 1
103
+ Impression.all.size.should eq 12
104
+ get "show", :id=> 2
105
+ Impression.all.size.should eq 13
106
+ get "show", :id => 2
107
+ Impression.all.size.should eq 13
108
+ get "index"
109
+ Impression.all.size.should eq 14
110
+ end
111
+
112
+ it "should log unique impressions only once per id" do
113
+ get "show", :id=> 1
114
+ Impression.all.size.should eq 12
115
+ get "show", :id=> 2
116
+ Impression.all.size.should eq 13
117
+ get "show", :id => 2
118
+ Impression.all.size.should eq 13
119
+ get "index"
120
+ Impression.all.size.should eq 14
121
+ end
122
+
123
+ end
124
+
125
+ end
@@ -0,0 +1,310 @@
1
+ require 'spec_helper'
2
+
3
+ # we use the posts controller as it uses the impressionsist module. any such controller would do.
4
+ describe DummyController do
5
+
6
+ before do
7
+ @impression_count = Impression.all.size
8
+ end
9
+
10
+ describe "impressionist filter uniqueness" do
11
+
12
+ it "should ignore uniqueness if not requested" do
13
+ controller.impressionist_subapp_filter(nil, nil)
14
+ controller.impressionist_subapp_filter(nil, nil)
15
+ Impression.should have(@impression_count + 2).records
16
+ end
17
+
18
+ it "should recognize unique session" do
19
+ controller.stub!(:session_hash).and_return(request.session_options[:id])
20
+ controller.impressionist_subapp_filter(nil, [:session_hash])
21
+ controller.impressionist_subapp_filter(nil, [:session_hash])
22
+ Impression.should have(@impression_count + 1).records
23
+ end
24
+
25
+ it "should recognize unique ip" do
26
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
27
+ controller.impressionist_subapp_filter(nil, [:ip_address])
28
+ controller.impressionist_subapp_filter(nil, [:ip_address])
29
+ Impression.should have(@impression_count + 1).records
30
+ end
31
+
32
+ it "should recognize unique request" do
33
+ controller.impressionist_subapp_filter(nil, [:request_hash])
34
+ controller.impressionist_subapp_filter(nil, [:request_hash])
35
+ Impression.should have(@impression_count + 1).records
36
+ end
37
+
38
+ it "should recognize unique action" do
39
+ controller.stub!(:action_name).and_return("test_action")
40
+ controller.impressionist_subapp_filter(nil, [:action_name])
41
+ controller.impressionist_subapp_filter(nil, [:action_name])
42
+ Impression.should have(@impression_count + 1).records
43
+ end
44
+
45
+ it "should recognize unique controller" do
46
+ controller.stub!(:controller_name).and_return("post")
47
+ controller.impressionist_subapp_filter(nil, [:controller_name])
48
+ controller.impressionist_subapp_filter(nil, [:controller_name])
49
+ Impression.should have(@impression_count + 1).records
50
+ end
51
+
52
+ it "should recognize unique user" do
53
+ controller.stub!(:user_id).and_return(42)
54
+ controller.impressionist_subapp_filter(nil, [:user_id])
55
+ controller.impressionist_subapp_filter(nil, [:user_id])
56
+ Impression.should have(@impression_count + 1).records
57
+ end
58
+
59
+ it "should recognize unique referer" do
60
+ controller.request.stub!(:referer).and_return("http://foo/bar")
61
+ controller.impressionist_subapp_filter(nil, [:referrer])
62
+ controller.impressionist_subapp_filter(nil, [:referrer])
63
+ Impression.should have(@impression_count + 1).records
64
+ end
65
+
66
+ it "should recognize unique id" do
67
+ controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
68
+ controller.impressionist_subapp_filter(nil, [:impressionable_id])
69
+ controller.impressionist_subapp_filter(nil, [:impressionable_id])
70
+ Impression.should have(@impression_count + 1).records
71
+ end
72
+
73
+ # extra redundant test for important controller and action combination.
74
+ it "should recognize different controller and action" do
75
+ controller.stub!(:controller_name).and_return("post")
76
+ controller.stub!(:action_name).and_return("test_action")
77
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
78
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
79
+ Impression.should have(@impression_count + 1).records
80
+ controller.stub!(:action_name).and_return("another_action")
81
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
82
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
83
+ Impression.should have(@impression_count + 2).records
84
+ controller.stub!(:controller_name).and_return("article")
85
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
86
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
87
+ Impression.should have(@impression_count + 3).records
88
+ end
89
+
90
+ it "should recognize different action" do
91
+ controller.stub!(:action_name).and_return("test_action")
92
+ controller.impressionist_subapp_filter(nil, [:action_name])
93
+ controller.impressionist_subapp_filter(nil, [:action_name])
94
+ Impression.should have(@impression_count + 1).records
95
+ controller.stub!(:action_name).and_return("another_action")
96
+ controller.impressionist_subapp_filter(nil, [:action_name])
97
+ controller.impressionist_subapp_filter(nil, [:action_name])
98
+ Impression.should have(@impression_count + 2).records
99
+ end
100
+
101
+ it "should recognize different controller" do
102
+ controller.stub!(:controller_name).and_return("post")
103
+ controller.impressionist_subapp_filter(nil, [:controller_name])
104
+ controller.impressionist_subapp_filter(nil, [:controller_name])
105
+ Impression.should have(@impression_count + 1).records
106
+ controller.stub!(:controller_name).and_return("article")
107
+ controller.impressionist_subapp_filter(nil, [:controller_name])
108
+ controller.impressionist_subapp_filter(nil, [:controller_name])
109
+ Impression.should have(@impression_count + 2).records
110
+ end
111
+
112
+ it "should recognize different session" do
113
+ controller.stub!(:session_hash).and_return("foo")
114
+ controller.impressionist_subapp_filter(nil, [:session_hash])
115
+ controller.impressionist_subapp_filter(nil, [:session_hash])
116
+ Impression.should have(@impression_count + 1).records
117
+ controller.stub!(:session_hash).and_return("bar")
118
+ controller.impressionist_subapp_filter(nil, [:session_hash])
119
+ controller.impressionist_subapp_filter(nil, [:session_hash])
120
+ Impression.should have(@impression_count + 2).records
121
+ end
122
+
123
+ it "should recognize different ip" do
124
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
125
+ controller.impressionist_subapp_filter(nil, [:ip_address])
126
+ controller.impressionist_subapp_filter(nil, [:ip_address])
127
+ Impression.should have(@impression_count + 1).records
128
+ controller.request.stub!(:remote_ip).and_return("5.6.7.8")
129
+ controller.impressionist_subapp_filter(nil, [:ip_address])
130
+ controller.impressionist_subapp_filter(nil, [:ip_address])
131
+ Impression.should have(@impression_count + 2).records
132
+ end
133
+
134
+ it "should recognize different referer" do
135
+ controller.request.stub!(:referer).and_return("http://foo/bar")
136
+ controller.impressionist_subapp_filter(nil, [:referrer])
137
+ controller.impressionist_subapp_filter(nil, [:referrer])
138
+ Impression.should have(@impression_count + 1).records
139
+ controller.request.stub!(:referer).and_return("http://bar/fo")
140
+ controller.impressionist_subapp_filter(nil, [:referrer])
141
+ controller.impressionist_subapp_filter(nil, [:referrer])
142
+ Impression.should have(@impression_count + 2).records
143
+ end
144
+
145
+ it "should recognize different id" do
146
+ controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
147
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
148
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
149
+ controller.stub!(:params).and_return({:id => "42"}) # for correct impressionable id in filter
150
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
151
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
152
+ Impression.should have(@impression_count + 2).records
153
+ end
154
+
155
+ it "should recognize combined uniqueness" do
156
+ controller.stub!(:action_name).and_return("test_action")
157
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :action_name])
158
+ controller.impressionist_subapp_filter(nil, [:request_hash, :ip_address, :action_name])
159
+ controller.impressionist_subapp_filter(nil, [:request_hash, :action_name])
160
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
161
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash])
162
+ controller.impressionist_subapp_filter(nil, [:action_name])
163
+ controller.impressionist_subapp_filter(nil, [:ip_address])
164
+ controller.impressionist_subapp_filter(nil, [:request_hash])
165
+ Impression.should have(@impression_count + 1).records
166
+ end
167
+
168
+ it "should recognize combined non-uniqueness" do
169
+ controller.stub!(:action_name).and_return(nil)
170
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
171
+ controller.stub!(:action_name).and_return("test_action")
172
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
173
+ controller.stub!(:action_name).and_return("another_action")
174
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
175
+ Impression.should have(@impression_count + 3).records
176
+ end
177
+
178
+ end
179
+
180
+ describe "impressionist method uniqueness for impressionables" do
181
+
182
+ # in this test we reuse the post model. might break if model changes.
183
+
184
+ it "should ignore uniqueness if not requested" do
185
+ impressionable = Post.create
186
+ controller.impressionist impressionable
187
+ controller.impressionist impressionable
188
+ Impression.should have(@impression_count + 2).records
189
+ end
190
+
191
+ it "should recognize unique session" do
192
+ controller.stub!(:session_hash).and_return(request.session_options[:id])
193
+ impressionable = Post.create
194
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
195
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
196
+ Impression.should have(@impression_count + 1).records
197
+ end
198
+
199
+ it "should recognize unique ip" do
200
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
201
+ impressionable = Post.create
202
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
203
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
204
+ Impression.should have(@impression_count + 1).records
205
+ end
206
+
207
+ it "should recognize unique request" do
208
+ impressionable = Post.create
209
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
210
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
211
+ Impression.should have(@impression_count + 1).records
212
+ end
213
+
214
+ it "should recognize unique user" do
215
+ controller.stub!(:user_id).and_return(666)
216
+ impressionable = Post.create
217
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
218
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
219
+ Impression.should have(@impression_count + 1).records
220
+ end
221
+
222
+ it "should recognize unique referer" do
223
+ controller.request.stub!(:referer).and_return("http://foo/bar")
224
+ impressionable = Post.create
225
+ controller.impressionist(impressionable, nil, :unique => [:referrer])
226
+ controller.impressionist(impressionable, nil, :unique => [:referrer])
227
+ Impression.should have(@impression_count + 1).records
228
+ end
229
+
230
+ it "should recognize different session" do
231
+ impressionable = Post.create
232
+ controller.stub!(:session_hash).and_return("foo")
233
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
234
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
235
+ Impression.should have(@impression_count + 1).records
236
+ controller.stub!(:session_hash).and_return("bar")
237
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
238
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
239
+ Impression.should have(@impression_count + 2).records
240
+ end
241
+
242
+ it "should recognize different ip" do
243
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
244
+ impressionable = Post.create
245
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
246
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
247
+ Impression.should have(@impression_count + 1).records
248
+ controller.request.stub!(:remote_ip).and_return("5.6.7.8")
249
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
250
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
251
+ Impression.should have(@impression_count + 2).records
252
+ end
253
+
254
+ it "should recognize different user" do
255
+ impressionable = Post.create
256
+ controller.stub!(:user_id).and_return(666)
257
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
258
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
259
+ Impression.should have(@impression_count + 1).records
260
+ controller.stub!(:user_id).and_return(42)
261
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
262
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
263
+ Impression.should have(@impression_count + 2).records
264
+ end
265
+
266
+ it "should recognize combined uniqueness" do
267
+ impressionable = Post.create
268
+ controller.stub!(:session_hash).and_return("foo")
269
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
270
+ controller.impressionist(impressionable, nil, :unique => [:request_hash, :ip_address, :session_hash])
271
+ controller.impressionist(impressionable, nil, :unique => [:request_hash, :session_hash])
272
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
273
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash])
274
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
275
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
276
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
277
+ Impression.should have(@impression_count + 1).records
278
+ end
279
+
280
+ it "should recognize combined non-uniqueness" do
281
+ impressionable = Post.create
282
+ controller.stub!(:session_hash).and_return(nil)
283
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
284
+ controller.stub!(:session_hash).and_return("foo")
285
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
286
+ controller.stub!(:session_hash).and_return("bar")
287
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
288
+ Impression.should have(@impression_count + 3).records
289
+ end
290
+
291
+ end
292
+
293
+ describe "impressionist filter and method uniqueness" do
294
+
295
+ it "should recognize uniqueness" do
296
+ impressionable = Post.create
297
+ controller.stub!(:controller_name).and_return("posts") # for correct impressionable type in filter
298
+ controller.stub!(:params).and_return({:id => impressionable.id.to_s}) # for correct impressionable id in filter
299
+ controller.stub!(:session_hash).and_return("foo")
300
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
301
+ # order of the following methods is important for the test!
302
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :session_hash])
303
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
304
+ Impression.should have(@impression_count + 1).records
305
+ end
306
+
307
+ end
308
+
309
+ end
310
+