candies 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,36 +1,6 @@
1
- # Candies[![travis-ci](https://secure.travis-ci.org/martinciu/candies.png?branch=master)](http://travis-ci.org/martinciu/candies)
2
- Invisible image based tracing service with Redis backend
3
-
4
- ## Requirements
5
-
6
- Candies uses redis as a datastore.
7
-
8
- Candies only supports redis 2.0 or greater.
9
-
10
- If you're on OS X, Homebrew is the simplest way to install Redis:
11
-
12
- $ brew install redis
13
- $ redis-server /usr/local/etc/redis.conf
14
-
15
- You now have a Redis daemon running on 6379.
16
-
17
- ## Setup
18
-
19
- If you are using bundler add candies to your Gemfile:
20
-
21
- gem 'candies'
22
-
23
- Then run:
24
-
25
- bundle install
26
-
27
- Otherwise install the gem:
28
-
29
- gem install candies
30
-
31
- and require it in your project:
32
-
33
- require 'candies'
1
+ # Candies
2
+ [![travis-ci](https://secure.travis-ci.org/martinciu/candies.png?branch=master)](http://travis-ci.org/martinciu/candies)
3
+ ####Invisible image based tracing service with Redis backend
34
4
 
35
5
  ## Usage
36
6
 
@@ -59,11 +29,11 @@ It will be available under `http://yourapproot.tld/candies` url
59
29
 
60
30
  When you have Candies server deployed you can add tracking payload by including `img` tag in your HTML code:
61
31
 
62
- <a href="http://candies.tld/anyfile.gif?id=tracing-id&foo=bar&baz=foo" />
32
+ <a href="http://candies.tld/trackername.gif?id=tracing-id&foo=bar&baz=foo" />
63
33
 
64
34
  or if you mounted candies in your rails app as `candies` then it will be:
65
35
 
66
- <a href="http://yourapproot.tld/candies/anyfile.gif?id=tracing-id&foo=bar&baz=foo" />
36
+ <a href="http://yourapproot.tld/candies/trackername.gif?id=tracing-id&foo=bar&baz=foo" />
67
37
 
68
38
  Also in rails app you can use `candies_image_tag` helper. To do so you have to set `Candies.url` to point to the candies service url. The best way is to put in `config/initializers/candies.rb` file:
69
39
 
@@ -71,9 +41,70 @@ Also in rails app you can use `candies_image_tag` helper. To do so you have to s
71
41
 
72
42
  Now you can use `candies_image_tag` helper in controller views and in mailer views. Example:
73
43
 
74
- <%= candies_image_tag(:id => "anyone@example.com", :email_type => "hello") %>
44
+ <%= candies_image_tag(:id => "anyone@example.com", :tracker => "t", :email_type => "hello") %>
45
+
46
+ Note that `id` parameter is required. If `tracker` parameter is ommited it will be set "t" as default. Rest of parameters is a tracking payload. In this case redis key will be: `candies:tracker:anyone@example.com:2011-11-10T13:13:09+01:00` and value: `"{\"email_type\":\"hello\"}"`. If you don't specify `id` parameter not value will be stored. Invisible image will by served anyway.
47
+
48
+ ## Results
49
+
50
+ There isn't any dashboard for displaying values. You can review gathered metrics in three ways:
51
+
52
+ ### JSON
53
+
54
+ You can get all data from candies server if you request it using JSON.
55
+
56
+ curl http://localhost:9393/tracker.json?id=10 |jsonpretty
57
+ {
58
+ "tracker:10:2011-11-19T22:39:34+01:00": "{\"foo\":\"99\"}",
59
+ "tracker:10:2011-11-19T22:23:09+01:00": "{\"foo\":\"39\"}",
60
+ "tracker:10:2011-11-19T22:24:26+01:00": "{\"foo\":\"94\"}"
61
+ }
62
+
63
+ Note: `id` parameter is optional.
75
64
 
76
- Note that `id` parameter is required. It will be used to create a redis key under which paload will be stored. In this case redis key will be: `candies:anyone@example.com:2011-11-10T13:13:09+01:00` and value: `"{\"email_type\":\"hello\"}"`. If you don't specify `id` parameter not value will be stored. Invisible image will by served anyway.
65
+ ### redis-cli
66
+
67
+ Just log to your Redis using redis command line interface. Keys started with `candies` so to display all keys from candies type
68
+
69
+ redis 127.0.0.1:6379> keys candies*
70
+ 1) "candies:tracker:10:2011-11-19T22:39:34+01:00"
71
+ 2) "candies:tracker:10:2011-11-19T22:23:09+01:00"
72
+ 3) "candies:tracker:10:2011-11-19T22:24:26+01:00"
73
+
74
+ ### redisplay
75
+
76
+ Use [redisplay](https://github.com/martinciu/redisplay) Simple Rack app for browsing Redis
77
+
78
+ ## Requirements
79
+
80
+ Candies uses redis as a datastore.
81
+
82
+ Candies only supports redis 2.0 or greater.
83
+
84
+ If you're on OS X, Homebrew is the simplest way to install Redis:
85
+
86
+ $ brew install redis
87
+ $ redis-server /usr/local/etc/redis.conf
88
+
89
+ You now have a Redis daemon running on 6379.
90
+
91
+ ## Setup
92
+
93
+ If you are using bundler add candies to your Gemfile:
94
+
95
+ gem 'candies'
96
+
97
+ Then run:
98
+
99
+ bundle install
100
+
101
+ Otherwise install the gem:
102
+
103
+ gem install candies
104
+
105
+ and require it in your project:
106
+
107
+ require 'candies'
77
108
 
78
109
  ## Configuration
79
110
 
@@ -127,10 +158,6 @@ Simply use the `Candies.redis.namespace` accessor:
127
158
  We recommend sticking this in your initializer somewhere after Redis
128
159
  is configured.
129
160
 
130
- ## Results
131
-
132
- There isn't any dashboard for displaying values (yet). You cen review them by logging into `redis-cli`. Sorry.
133
-
134
161
  ## Development
135
162
 
136
163
  Source hosted at [GitHub](http://github.com/martinciu/candies).
@@ -1,7 +1,7 @@
1
1
  module Candies
2
2
  module Helper
3
3
  def candies_image_tag(args)
4
- image_tag("#{Candies.url}/t.gif?#{args.to_query}", :alt => "", :width => 1, :height => 1) if Candies.url
4
+ image_tag("#{Candies.url}/#{args.fetch(:tracker) {|t| "t"}}.gif?#{args.to_query}", :alt => "", :width => 1, :height => 1) if Candies.url
5
5
  end
6
6
  end
7
7
  end
@@ -1,26 +1,14 @@
1
- module Candies
2
- class Server
3
- def call(env)
4
- req = Rack::Request.new(env)
5
- id = req.params.delete("id")
6
- Candies.redis.set([id, Time.now.iso8601].join(":"), req.params.to_json) if !id.nil?
7
- [200, headers, [image]]
8
- end
9
-
10
- private
11
- def headers
12
- {
13
- "Content-Type" => "image/gif",
14
- "Content-Length" => "35",
15
- "Cache-Control" => "no-store, no-cache, must-revalidate, private",
16
- "Pragma" => "no-cache",
17
- "Expires" => "Sat, 25 Nov 2000 05:00:00 GMT"
18
- }
19
- end
1
+ require "candies/server/base"
2
+ require "candies/server/json"
3
+ require "candies/server/gif"
20
4
 
21
- def image
22
- "GIF89a\u0001\u0000\u0001\u0000\x80\xFF\u0000\xFF\xFF\xFF\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;"
5
+ module Candies
6
+ module Server
7
+ def self.new
8
+ Rack::Builder.new do
9
+ use Rack::ContentLength
10
+ run Candies::Server::Base.new(:gif => Candies::Server::Gif.new, :json => Candies::Server::Json.new)
23
11
  end
24
-
12
+ end
25
13
  end
26
14
  end
@@ -0,0 +1,34 @@
1
+ module Candies
2
+ module Server
3
+ class Base
4
+ attr_accessor :request, :id, :responders
5
+
6
+ def initialize(responders = {})
7
+ @responders = responders
8
+ end
9
+
10
+ def call(env)
11
+ @request = Rack::Request.new(env)
12
+ @responders.fetch(format) {@responders[:json]}.call(env)
13
+ end
14
+
15
+ protected
16
+ def format
17
+ @request.path.split(".").last.to_sym
18
+ end
19
+
20
+ def tracker
21
+ @request.path.match(/^\/(\w+)\.?(\w+$)?/)[1]
22
+ end
23
+
24
+ def id
25
+ @id ||= @request.params.delete("id")
26
+ end
27
+
28
+ def status
29
+ 200
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ module Candies
2
+ module Server
3
+ class Gif < Base
4
+
5
+ def call(env)
6
+ @request = Rack::Request.new(env)
7
+ Candies.redis.set(key, @request.params.to_json) if !id.nil?
8
+ [status, headers, body]
9
+ end
10
+
11
+ protected
12
+ def headers
13
+ {
14
+ "Content-Type" => "image/gif",
15
+ "Cache-Control" => "no-store, no-cache, must-revalidate, private",
16
+ "Pragma" => "no-cache",
17
+ "Expires" => "Sat, 25 Nov 2000 05:00:00 GMT"
18
+ }
19
+ end
20
+
21
+ def body
22
+ ["GIF89a\u0001\u0000\u0001\u0000\x80\xFF\u0000\xFF\xFF\xFF\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;"]
23
+ end
24
+
25
+ def key
26
+ [tracker, id, Time.now.iso8601].join(":")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module Candies
2
+ module Server
3
+ class Json < Base
4
+
5
+ def call(env)
6
+ @request = Rack::Request.new(env)
7
+ [status, headers, body]
8
+ end
9
+
10
+ protected
11
+ def headers
12
+ {
13
+ "Content-Type" => "application/json"
14
+ }
15
+ end
16
+
17
+ def key
18
+ "#{[tracker, id].compact.join(":")}*"
19
+ end
20
+
21
+ def body
22
+ [Candies.redis.keys(key).inject({}) {|body, k| body[k] = Candies.redis.get(k);body }.to_json]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Candies
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Candies::Helper do
4
+
5
+ class View
6
+ include Candies::Helper
7
+ end
8
+
9
+ Candies.url = "http://example.com"
10
+
11
+ before do
12
+ @view = View.new
13
+ @args = mock()
14
+ @args.stubs(:to_query).returns("a=10&c=foo")
15
+ end
16
+
17
+ describe "#candies_image_tag" do
18
+ it "call image_tag with tracker param" do
19
+ @args.expects(:fetch).with(:tracker).returns("custom")
20
+ @view.expects(:image_tag).with("http://example.com/custom.gif?a=10&c=foo", :alt => "", :width => 1, :height => 1)
21
+ @view.candies_image_tag(@args)
22
+ end
23
+
24
+ end
25
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Candies::Server do
3
+ describe Candies::Server::Gif do
4
4
  include Rack::Test::Methods
5
5
 
6
6
  before do
@@ -19,7 +19,7 @@ describe Candies::Server do
19
19
  it "get /t.gif?id=info@example.com&foo=bar adds record" do
20
20
  now = Time.now
21
21
  Timecop.freeze(now)
22
- @redis.expects(:set).with(["info@example.com", now.iso8601].join(":"), {:foo => "bar"}.to_json)
22
+ @redis.expects(:set).with(["t", "info@example.com", now.iso8601].join(":"), {:foo => "bar"}.to_json)
23
23
  get '/t.gif?id=info@example.com&foo=bar'
24
24
  last_response.status.must_equal 200
25
25
  last_response['Content-Type'].must_equal 'image/gif'
@@ -37,8 +37,8 @@ describe Candies::Server do
37
37
  it "get /t.gif?id=info@example.com adds record with empty payload" do
38
38
  now = Time.now
39
39
  Timecop.freeze(now)
40
- @redis.expects(:set).with(["info@example.com", now.iso8601].join(":"), {}.to_json)
41
- get '/t.gif?id=info@example.com'
40
+ @redis.expects(:set).with(["tracker", "info@example.com", now.iso8601].join(":"), {}.to_json)
41
+ get '/tracker.gif?id=info@example.com'
42
42
  last_response.status.must_equal 200
43
43
  last_response['Content-Type'].must_equal 'image/gif'
44
44
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Candies::Server do
4
+ include Rack::Test::Methods
5
+
6
+ before do
7
+ @redis = mock()
8
+ Candies.stubs(:redis).returns(@redis)
9
+ end
10
+
11
+ def app
12
+ @app ||= Candies::Server.new
13
+ end
14
+
15
+ it "get /t.json returns all records for t metric" do
16
+ values = [:foo, :bar]
17
+ @redis.expects(:get).with(:foo).returns("baz")
18
+ @redis.expects(:get).with(:bar).returns("foo")
19
+
20
+ @redis.expects(:keys).with("t*").returns(values)
21
+ get '/t.json'
22
+ last_response.status.must_equal 200
23
+ last_response['Content-Type'].must_equal 'application/json'
24
+ end
25
+
26
+ it "get /t.gif?&id=foo returns records for id=foo" do
27
+ values = [:foo, :bar]
28
+ @redis.expects(:get).with(:foo).returns("baz")
29
+ @redis.expects(:get).with(:bar).returns("foo")
30
+
31
+ @redis.expects(:keys).with("t:foo*").returns(values)
32
+ get '/t.json?&id=foo'
33
+ last_response.status.must_equal 200
34
+ last_response['Content-Type'].must_equal 'application/json'
35
+ end
36
+
37
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: candies
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-10 00:00:00.000000000 Z
12
+ date: 2011-11-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &70237840036260 !ruby/object:Gem::Requirement
16
+ requirement: &70267951013440 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.3.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70237840036260
24
+ version_requirements: *70267951013440
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis
27
- requirement: &70237840035400 !ruby/object:Gem::Requirement
27
+ requirement: &70267951012480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.2.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70237840035400
35
+ version_requirements: *70267951012480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redis-namespace
38
- requirement: &70237840034480 !ruby/object:Gem::Requirement
38
+ requirement: &70267951011580 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.3
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70237840034480
46
+ version_requirements: *70267951011580
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: json
49
- requirement: &70237840032740 !ruby/object:Gem::Requirement
49
+ requirement: &70267951010600 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.5.3
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70237840032740
57
+ version_requirements: *70267951010600
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &70237840047340 !ruby/object:Gem::Requirement
60
+ requirement: &70267951009620 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 0.9.2
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70237840047340
68
+ version_requirements: *70267951009620
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest
71
- requirement: &70237840045180 !ruby/object:Gem::Requirement
71
+ requirement: &70267951008760 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 2.7.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70237840045180
79
+ version_requirements: *70267951008760
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rack-test
82
- requirement: &70237840042840 !ruby/object:Gem::Requirement
82
+ requirement: &70267951007680 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0.6'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70237840042840
90
+ version_requirements: *70267951007680
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: turn
93
- requirement: &70237840039340 !ruby/object:Gem::Requirement
93
+ requirement: &70267951023220 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 0.8.3
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70237840039340
101
+ version_requirements: *70267951023220
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: mocha
104
- requirement: &70237840054200 !ruby/object:Gem::Requirement
104
+ requirement: &70267951022460 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 0.10.0
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70237840054200
112
+ version_requirements: *70267951022460
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: timecop
115
- requirement: &70237840052480 !ruby/object:Gem::Requirement
115
+ requirement: &70267951021760 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: 0.3.5
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70237840052480
123
+ version_requirements: *70267951021760
124
124
  description: Invisible image based tracing service with Redis backend
125
125
  email:
126
126
  - marcin.ciunelis@gmail.com
@@ -139,8 +139,13 @@ files:
139
139
  - lib/candies.rb
140
140
  - lib/candies/helper.rb
141
141
  - lib/candies/server.rb
142
+ - lib/candies/server/base.rb
143
+ - lib/candies/server/gif.rb
144
+ - lib/candies/server/json.rb
142
145
  - lib/candies/version.rb
143
- - spec/candies/server_spec.rb
146
+ - spec/candies/helper_spec.rb
147
+ - spec/candies/server/gif_spec.rb
148
+ - spec/candies/server/json_spec.rb
144
149
  - spec/spec_helper.rb
145
150
  homepage: ''
146
151
  licenses: []
@@ -156,7 +161,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
156
161
  version: '0'
157
162
  segments:
158
163
  - 0
159
- hash: -4015693725382346057
164
+ hash: -2058818266629124407
160
165
  required_rubygems_version: !ruby/object:Gem::Requirement
161
166
  none: false
162
167
  requirements:
@@ -165,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
170
  version: '0'
166
171
  segments:
167
172
  - 0
168
- hash: -4015693725382346057
173
+ hash: -2058818266629124407
169
174
  requirements: []
170
175
  rubyforge_project:
171
176
  rubygems_version: 1.8.10
@@ -173,5 +178,7 @@ signing_key:
173
178
  specification_version: 3
174
179
  summary: ''
175
180
  test_files:
176
- - spec/candies/server_spec.rb
181
+ - spec/candies/helper_spec.rb
182
+ - spec/candies/server/gif_spec.rb
183
+ - spec/candies/server/json_spec.rb
177
184
  - spec/spec_helper.rb