dash-mario 0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +93 -0
- data/Gemfile +16 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +100 -0
- data/Rakefile +34 -0
- data/dash-mario.gemspec +22 -0
- data/lib/dash-fu/mario.rb +154 -0
- data/lib/dash-fu/marios/backtweets.rb +57 -0
- data/lib/dash-fu/marios/backtweets.yml +9 -0
- data/lib/dash-fu/marios/github.rb +110 -0
- data/lib/dash-fu/marios/github.yml +15 -0
- data/lib/dash-fu/marios/github_issues.rb +91 -0
- data/lib/dash-fu/marios/github_issues.yml +14 -0
- data/lib/dash-fu/marios/ruby_gems.rb +55 -0
- data/lib/dash-fu/marios/ruby_gems.yml +6 -0
- data/test/api_keys.yml +1 -0
- data/test/backtweets_test.rb +151 -0
- data/test/cassettes/backtweets.yml +63 -0
- data/test/cassettes/github.yml +126 -0
- data/test/cassettes/github_issues.yml +123 -0
- data/test/cassettes/ruby_gems.yml +36 -0
- data/test/github_issues_test.rb +194 -0
- data/test/github_test.rb +251 -0
- data/test/helpers/activity.rb +21 -0
- data/test/helpers/metric.rb +22 -0
- data/test/helpers/person.rb +25 -0
- data/test/helpers/test.rb +161 -0
- data/test/ruby_gems_test.rb +164 -0
- data/test/setup.rb +31 -0
- data/test/test.log +852 -0
- metadata +164 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
2010-09-07 v0.15 Renamed to DashFu::Mario
|
2
|
+
|
3
|
+
2010-09-07 v0.14 RubyGems and Github identities
|
4
|
+
|
5
|
+
RubyGems releases now identify RubyGems as the source of the activity.
|
6
|
+
|
7
|
+
Github source includes github login name as identity.
|
8
|
+
|
9
|
+
2010-08-31 v0.13 Github data source merges related commits
|
10
|
+
|
11
|
+
Now it does.
|
12
|
+
|
13
|
+
2010-08-31 v0.12 Github data source merges related commits
|
14
|
+
|
15
|
+
Github data source merges related commits (same committer/time) into single
|
16
|
+
activity and shows first line of all commit messages.
|
17
|
+
|
18
|
+
Changed to coding/testing with Ruby 1.9.2, since this is the target
|
19
|
+
environment.
|
20
|
+
|
21
|
+
2010-08-30 v0.11 Changes to activity person, AS 3.0 support
|
22
|
+
|
23
|
+
Activity's person name is now fullname, photo is photo_url and url is no
|
24
|
+
longer, but we do accept multiple identities of the form domain:id, e.g
|
25
|
+
twitter.com:assaf, linkedin.com:assafarkin.
|
26
|
+
|
27
|
+
Test suite now allows validating metric, activity and person. Call the validate
|
28
|
+
method to run validation and raise exception on error (with a helpful error
|
29
|
+
message). Call valid? if you're only interested in true/false.
|
30
|
+
|
31
|
+
Gem dependencies removed to allow running with ActiveSupport 3.0.
|
32
|
+
|
33
|
+
2010-08-26 v0.10 Tags and better messages
|
34
|
+
|
35
|
+
Activities can now include tags.
|
36
|
+
|
37
|
+
Improvement all around to all the HTML messages.
|
38
|
+
|
39
|
+
2010-08-25 v0.9 Better Github commit message
|
40
|
+
|
41
|
+
2010-08-24 v0.8 Minor API change
|
42
|
+
|
43
|
+
Attribute :id is now :uid.
|
44
|
+
|
45
|
+
Activity content can be set using either :html or :text attribute.
|
46
|
+
2010-08-24 v0.7 Added test suite and resources
|
47
|
+
|
48
|
+
Each source can have an associated resources file (YAML), e.g. ruby_gems.rb
|
49
|
+
would have ruby_gems.yml. The default implementation of methods like name,
|
50
|
+
description and display pull content from the resource. Resources can support
|
51
|
+
multiple languages, but we're starting with just EN.
|
52
|
+
|
53
|
+
Some sources also need API keys. These are accessed using the method api_key
|
54
|
+
that returns the API key value for the current source (often a string, but can
|
55
|
+
also be hash or array). There's an api_keys.yml file which contains fake API
|
56
|
+
keys. You can put a real key in there while generating a cassette for your test
|
57
|
+
case.
|
58
|
+
|
59
|
+
Test suite is here, using WebMock and VCR to rest API calls. Cassettes go in
|
60
|
+
test/cassettes, fixtures in test/fixtures.
|
61
|
+
|
62
|
+
2010-08-19 v0.6 Added Backtweet
|
63
|
+
|
64
|
+
2010-08-19 v0.5 Added Github and Github issues
|
65
|
+
|
66
|
+
2010-08-18 v0.4 Metrics that set and increment
|
67
|
+
|
68
|
+
Revised setup method to change special values metric.name and metric.columns
|
69
|
+
(was name and column).
|
70
|
+
|
71
|
+
There are two types of metrics, those that collect totals and those that
|
72
|
+
collect daily/hourly values. The setup method indicates that by setting the
|
73
|
+
value metric.total (defaults to false).
|
74
|
+
|
75
|
+
Revised update method to allow either setting current value (:set) or
|
76
|
+
incrementing current value (:inc).
|
77
|
+
|
78
|
+
2010-08-11 v0.3 Always be sending changes
|
79
|
+
|
80
|
+
Changed: Collector update methods accepts inc and timestamp arguments (but set
|
81
|
+
is gone).
|
82
|
+
|
83
|
+
Fixed: Rubygems source captures most recent downloads count as meta-data,
|
84
|
+
updates collector with change since last update.
|
85
|
+
|
86
|
+
Fixed: Rubygems source can handle whatever name you throw at it and properly
|
87
|
+
escapes it.
|
88
|
+
|
89
|
+
2010-08-10 v0.2 Working Rubygems source
|
90
|
+
|
91
|
+
Fixed: Rubygems source not updating meta data like authors, project info, URL.
|
92
|
+
|
93
|
+
2010-08-09 v0.1 First release
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 Assaf Arkin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
{Dash-fu}[http://dash-fu.com] sources need to get their data somehow: enter
|
2
|
+
Marios. Marios are the brave workers that go out and collect data from vaious
|
3
|
+
data sources and report them back in the form of activities and metrics.
|
4
|
+
|
5
|
+
|
6
|
+
== Setup
|
7
|
+
|
8
|
+
A Mario is setup in four steps. First, the display method returns an HTML form
|
9
|
+
which will be displayed to the user. In fact, this method returns two values:
|
10
|
+
|
11
|
+
* inputs -- HTML input controls for setting up a new controller.
|
12
|
+
* notes -- Additional setup notes, e.g. other steps that need to be
|
13
|
+
followed, what values to supply, etc.
|
14
|
+
|
15
|
+
Wrap input controls within the label and use the source[..param..] notation for
|
16
|
+
the name attribute. For example, for Twitter:
|
17
|
+
|
18
|
+
<label>Screen name <input type="text" name="source[screen_name]" size="30"></label>
|
19
|
+
|
20
|
+
When the form is filled, the setup method is called with a context and values
|
21
|
+
from the form fields. Since the Mario needs to store state information, it uses
|
22
|
+
the context for that. The context is a Hash that can store basic Ruby values
|
23
|
+
(nil, String, boolean, Numeric, Array and Hash).
|
24
|
+
|
25
|
+
Some sources collect metrics. These sources must set three specific values
|
26
|
+
(during setup):
|
27
|
+
|
28
|
+
* metric.name -- The name of the metric, e.g. Twitter source might use the
|
29
|
+
name "Twitter mentions of @dash_fu".
|
30
|
+
* metric.columns -- Specifies the columns (at least one) that make up this
|
31
|
+
metric. The value if an array where each item describes a single column, see
|
32
|
+
below for more details.
|
33
|
+
* metric.totals -- True if this metric collects totals (life-time values,
|
34
|
+
e.g. downloads, user accounts), false if it only collects daily values (e.g.
|
35
|
+
average response time, number of instances in cluster).
|
36
|
+
|
37
|
+
For metric.columns, each item can use the following keys:
|
38
|
+
|
39
|
+
* id -- Column identifier (if missing, derived from column name)
|
40
|
+
* name -- Column name (required)
|
41
|
+
|
42
|
+
Shortly after setup, the validate method is called with the same context. If it
|
43
|
+
raises any exception, the error is displayed to the user and the source is
|
44
|
+
discarded. Otherwise, register is called with a Webhook URL. Some Marios use
|
45
|
+
that to register the Webhook with another service.
|
46
|
+
|
47
|
+
|
48
|
+
== Updates
|
49
|
+
|
50
|
+
Periodically, the Mario will be asked to update the source by calling the update
|
51
|
+
method. This method is called with the same context and a block. If data comes
|
52
|
+
from a webhook, then the second argument to update is a Rack::Request object.
|
53
|
+
|
54
|
+
The block passed to update can be used to update the source by yielding to it
|
55
|
+
with a hash of named arguments. A single update may yield any number of times
|
56
|
+
with any combination of arguments.
|
57
|
+
|
58
|
+
The named arguments are:
|
59
|
+
|
60
|
+
* set -- Columns to set (metric). Records the most recent value for this
|
61
|
+
metric. This is a hash where the keys are column ids (or indexes), the values
|
62
|
+
are integers or floats.
|
63
|
+
* inc -- Columns to increment (metric). Records a change in value which may
|
64
|
+
be positive or negative. This is a hash where the keys are column ids (or
|
65
|
+
indexes), the values are integers or floats.
|
66
|
+
* timestamp -- The Time (if missing, uses the current system time).
|
67
|
+
* activity -- Activity to show in the stream. See below.
|
68
|
+
|
69
|
+
Activity can specify the following attributes:
|
70
|
+
|
71
|
+
* uid -- Unique identifier (within the scope of this source). For example,
|
72
|
+
if activity is a release, this could be the version number.
|
73
|
+
* html -- HTML contents of the activity.
|
74
|
+
* text -- Text contents of the activity (can be used instead of html).
|
75
|
+
* url -- URL for original resource (e.g. blog post, tweet).
|
76
|
+
* tags -- Any number of tags for filtering activities like this (e.g.
|
77
|
+
twitter, mention). Tags are lowercased and can contain alphanumeric, dashes
|
78
|
+
and underscore.
|
79
|
+
* person -- Person who performed this activity. A hash with the (all
|
80
|
+
optional) values :name, :email, :url and :photo.
|
81
|
+
* timestamp -- Timestamp activity occurred.
|
82
|
+
|
83
|
+
HTML can contain links (HTTP/S and email), images, bold, italics, paragraphs,
|
84
|
+
block quotes, lists, tables, pre-formatted text, video and a few other elements.
|
85
|
+
Scripts, objects, styles are obviously not allowed.
|
86
|
+
|
87
|
+
Occasionally, the meta method is called. This method is used to display
|
88
|
+
meta-data from the most recent state (i.e. last update). It returns an array of
|
89
|
+
fields, each being a hash with the following values:
|
90
|
+
|
91
|
+
* title -- Title for this field (not required)
|
92
|
+
* text -- Text to show as value of the field
|
93
|
+
* url -- Link (not required)
|
94
|
+
|
95
|
+
|
96
|
+
== Teardown
|
97
|
+
|
98
|
+
Eventually the source is destroyed and the Webhook is unregistered by
|
99
|
+
calling unregister.
|
100
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
# -- Building stuff --
|
4
|
+
|
5
|
+
spec = Gem::Specification.load(Dir["*.gemspec"].first)
|
6
|
+
|
7
|
+
desc "Build the Gem"
|
8
|
+
task :build do
|
9
|
+
sh "gem build #{spec.name}.gemspec"
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Install #{spec.name} locally"
|
13
|
+
task :install=>:build do
|
14
|
+
sudo = "sudo" unless File.writable?( Gem::ConfigMap[:bindir])
|
15
|
+
sh "#{sudo} gem install #{spec.name}-#{spec.version}.gem"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Push new release to gemcutter and git tag"
|
19
|
+
task :push=>["test", "build"] do
|
20
|
+
sh "git push"
|
21
|
+
puts "Tagging version #{spec.version} .."
|
22
|
+
sh "git tag v#{spec.version}"
|
23
|
+
sh "git push --tag"
|
24
|
+
puts "Building and pushing gem .."
|
25
|
+
sh "gem push #{spec.name}-#{spec.version}.gem"
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
task :default=>:test
|
30
|
+
Rake::TestTask.new do |task|
|
31
|
+
task.test_files = FileList['test/**/*_test.rb']
|
32
|
+
#task.warning = true
|
33
|
+
task.verbose = true
|
34
|
+
end
|
data/dash-mario.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "dash-mario"
|
3
|
+
spec.version = "0.15"
|
4
|
+
spec.author = "Assaf Arkin"
|
5
|
+
spec.email = "assaf@labnotes.org"
|
6
|
+
spec.homepage = "http://dash-fu.com"
|
7
|
+
spec.summary = "Hopping around collecting data, keeping your dashes dashing"
|
8
|
+
|
9
|
+
spec.files = Dir["{bin,lib,test}/**/*", "CHANGELOG", "MIT-LICENSE", "README.rdoc", "Rakefile", "Gemfile", "*.gemspec"]
|
10
|
+
|
11
|
+
spec.has_rdoc = true
|
12
|
+
spec.extra_rdoc_files = "README.rdoc", "CHANGELOG"
|
13
|
+
spec.rdoc_options = "--title", "DashFu::Mario #{spec.version}", "--main", "README.rdoc",
|
14
|
+
"--webcvs", "http://github.com/assaf/#{spec.name}"
|
15
|
+
|
16
|
+
spec.required_ruby_version = '>= 1.8.7'
|
17
|
+
spec.add_dependency "activesupport"
|
18
|
+
spec.add_dependency "json"
|
19
|
+
spec.add_dependency "nokogiri"
|
20
|
+
spec.add_dependency "rack"
|
21
|
+
spec.add_dependency "i18n"
|
22
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "json"
|
3
|
+
require "net/http"
|
4
|
+
require "rack"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
# See http://dash-fu.com
|
8
|
+
module DashFu
|
9
|
+
|
10
|
+
# The README covers it all.
|
11
|
+
module Mario
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :logger
|
15
|
+
|
16
|
+
# Returns all available marios.
|
17
|
+
def all
|
18
|
+
@marios ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns Mario by its identifier.
|
22
|
+
def find(id)
|
23
|
+
all[id]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Loads all the Marios from the given directory. The Mario identifier is
|
27
|
+
# derived from the filename (e.g. all/my_hero.rb becomes "my_hero"). The
|
28
|
+
# Mario class must map to the source identifier within the Mario module,
|
29
|
+
# e.g. DashFu::Mario::MyHero).
|
30
|
+
def load_marios(path = File.dirname(__FILE__) + "/marios")
|
31
|
+
Dir["#{path}/*.rb"].each do |file|
|
32
|
+
id = File.basename(file, ".rb")
|
33
|
+
fail "Mario #{id} already loaded" if all[id]
|
34
|
+
load file
|
35
|
+
klass = Mario.const_get(id.camelize)
|
36
|
+
all[id] = klass.new
|
37
|
+
logger.info "Loaded Mario #{id}: #{klass}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# API keys (see instance method api_key).
|
42
|
+
attr_accessor :api_keys
|
43
|
+
|
44
|
+
def included(klass)
|
45
|
+
klass.extend ClassMethods
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
# Mario identifier.
|
52
|
+
def mario_id
|
53
|
+
@mario_id ||= name.demodulize.underscore
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Returns the display name for this Mario.
|
59
|
+
#
|
60
|
+
# Uses the resource 'name', and fallbacks on the class name (e.g
|
61
|
+
# Mario::OneUp becomes "One Up").
|
62
|
+
def name
|
63
|
+
resources["name"] || mario_id.titleize
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns additional information about this source.
|
67
|
+
#
|
68
|
+
# A good description helps the user identity source and decide whether or
|
69
|
+
# not to use it.
|
70
|
+
#
|
71
|
+
# Uses the resource 'description'.
|
72
|
+
def description
|
73
|
+
resources["description"]
|
74
|
+
end
|
75
|
+
|
76
|
+
# This method returns a hash with two values:
|
77
|
+
# * inputs -- HTML fragment for a setup form
|
78
|
+
# * notes -- HTML fragment for setup notes
|
79
|
+
#
|
80
|
+
# Uses the resources 'inputs' and 'notes'.
|
81
|
+
def display
|
82
|
+
{ :inputs=>resources["inputs"], :notes=>resources["notes"] }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Called to setup a new source with parameters from the HTML form (see
|
86
|
+
# #display). If there are any missing values, report them when #validate is
|
87
|
+
# called.
|
88
|
+
def setup(source, params)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Called to validate the source. If there are any error, raise an
|
92
|
+
# exception. A good error message will help the user understand which value
|
93
|
+
# is missing or invalid and how to correct that.
|
94
|
+
def validate(source)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Called to register a Webhook (for sources that need it)
|
98
|
+
def register(source, url)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Called to update the source. This method will be called periodically with
|
102
|
+
# a source and a block. When triggered by a Webhook, it will be called with
|
103
|
+
# source, Rack::Request and a block. It can yield to the block any number of
|
104
|
+
# times with any combination of the supported named arguments for updating
|
105
|
+
# the source.
|
106
|
+
def update(source, request, &block)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Called to unregister a Webhook (for sources that don't need it).
|
110
|
+
def unregister(source, url)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns meta-data to be displayed alongside any other data. This method
|
114
|
+
# should return an array of hashes, each with the keys title (optional),
|
115
|
+
# text and url (optional). Good meta-data provides timely and relevant
|
116
|
+
# information that is not available in the raw data.
|
117
|
+
def meta(source)
|
118
|
+
[]
|
119
|
+
end
|
120
|
+
|
121
|
+
protected
|
122
|
+
|
123
|
+
# Source identifier.
|
124
|
+
def mario_id
|
125
|
+
self.class.mario_id
|
126
|
+
end
|
127
|
+
|
128
|
+
# Logger. Dump messages that can help with troubleshooting.
|
129
|
+
def logger
|
130
|
+
DashFu::Mario.logger
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns I18n resources for this gem.
|
134
|
+
def resources
|
135
|
+
unless @resources
|
136
|
+
file_name = File.dirname(__FILE__) + "/marios/#{mario_id}.yml"
|
137
|
+
@resources = File.exist?(file_name) ? YAML.load_file(file_name)["en"] : {}
|
138
|
+
end
|
139
|
+
@resources
|
140
|
+
end
|
141
|
+
|
142
|
+
# Shortcut for Rack::Utils.escape_html
|
143
|
+
def escape_html(text)
|
144
|
+
Rack::Utils.escape_html(text.to_s)
|
145
|
+
end
|
146
|
+
alias :h :escape_html
|
147
|
+
|
148
|
+
# Returns API key for this source. May return string or hash, depending on
|
149
|
+
# the API.
|
150
|
+
def api_key
|
151
|
+
@api_key ||= DashFu::Mario.api_keys[mario_id] or raise "No API key for #{mario_id}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|