dash-mario 0.15

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.
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