dash-mario 0.15

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org/"
2
+ gemspec
3
+
4
+ group :development do
5
+ gem "rake"
6
+ gem "yard"
7
+ end
8
+
9
+ group :test do
10
+ gem "awesome_print"
11
+ gem "nokogiri"
12
+ gem "shoulda"
13
+ gem "timecop"
14
+ gem "vcr"
15
+ gem "webmock"
16
+ end
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
@@ -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