pinball_wizard 0.0.1.pre → 0.3.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.
- checksums.yaml +5 -13
- data/.gitignore +9 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +32 -0
- data/LICENSE +21 -0
- data/README.md +336 -0
- data/Rakefile +4 -0
- data/bower.json +14 -0
- data/dist/css_tagger.js +42 -0
- data/dist/css_tagger.min.js +3 -0
- data/dist/pinball_wizard.js +227 -0
- data/gulpfile.js +40 -0
- data/karma.conf.js +66 -0
- data/lib/pinball_wizard.rb +5 -0
- data/lib/pinball_wizard/configuration.rb +17 -0
- data/lib/pinball_wizard/dsl.rb +38 -0
- data/lib/pinball_wizard/feature.rb +52 -0
- data/lib/pinball_wizard/helpers/hash.rb +26 -0
- data/lib/pinball_wizard/null_feature.rb +7 -0
- data/lib/pinball_wizard/railtie.rb +9 -0
- data/lib/pinball_wizard/registry.rb +44 -0
- data/lib/pinball_wizard/version.rb +3 -0
- data/lib/pinball_wizard/view_helpers/rails.rb +13 -0
- data/lib/pinball_wizard/view_helpers/sinatra/slim.rb +15 -0
- data/package.json +45 -0
- data/pinball_wizard.gemspec +20 -0
- data/spec/pinball_wizard/dsl_spec.rb +73 -0
- data/spec/pinball_wizard/feature_spec.rb +89 -0
- data/spec/pinball_wizard/registry_spec.rb +56 -0
- data/src/css_tagger.coffee +44 -0
- data/src/pinball_wizard.coffee +157 -0
- data/test/spec/css_tagger_spec.coffee +50 -0
- data/test/spec/pinball_wizard_spec.coffee +268 -0
- data/test/test-main.coffee +25 -0
- metadata +47 -10
data/bower.json
ADDED
data/dist/css_tagger.js
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
(function() {
|
2
|
+
define(function() {
|
3
|
+
return function(ele, pinballQueue, searchQuery) {
|
4
|
+
var add, classNames, entry, feature, featureNames, matches, state, _i, _j, _len, _len1, _ref;
|
5
|
+
classNames = [];
|
6
|
+
add = function(name) {
|
7
|
+
return classNames.push('use-' + name.split('_').join('-'));
|
8
|
+
};
|
9
|
+
for (_i = 0, _len = pinballQueue.length; _i < _len; _i++) {
|
10
|
+
entry = pinballQueue[_i];
|
11
|
+
if (!entry.length) {
|
12
|
+
continue;
|
13
|
+
}
|
14
|
+
switch (entry[0]) {
|
15
|
+
case 'activate':
|
16
|
+
add(entry[1]);
|
17
|
+
break;
|
18
|
+
case 'add':
|
19
|
+
_ref = entry[1];
|
20
|
+
for (feature in _ref) {
|
21
|
+
state = _ref[feature];
|
22
|
+
if (state === 'active') {
|
23
|
+
add(feature);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
matches = searchQuery.match(/pinball=([a-z-_,]+)/i);
|
29
|
+
if (matches && matches.length > 1) {
|
30
|
+
featureNames = (matches[1] + '').split(',');
|
31
|
+
for (_j = 0, _len1 = featureNames.length; _j < _len1; _j++) {
|
32
|
+
feature = featureNames[_j];
|
33
|
+
add(feature);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
if (ele) {
|
37
|
+
ele.className += ' ' + classNames.join(' ');
|
38
|
+
}
|
39
|
+
};
|
40
|
+
});
|
41
|
+
|
42
|
+
}).call(this);
|
@@ -0,0 +1,3 @@
|
|
1
|
+
// Minified on http://closure-compiler.appspot.com/ using Advanced settings
|
2
|
+
|
3
|
+
(function(g,d,e){var f,h,b,a,c,l,k;h=[];f=function(a){h.push("use-"+a.split("_").join("-"))};c=0;for(l=d.length;c<l;c++)if(b=d[c],b.length)switch(b[0]){case "activate":f(b[1]);break;case "add":for(a in k=b[1],k)b=k[a],"active"===b&&f(a)}if((a=e.match(/pinball=([a-z-_,]+)/i))&&1<a.length)for(d=(a[1]+"").split(","),e=0,c=d.length;e<c;e++)a=d[e],f(a);g&&(g.className+=" "+h.join(" "))})(document.documentElement,window.pinball,window.location.search);
|
@@ -0,0 +1,227 @@
|
|
1
|
+
(function() {
|
2
|
+
'use strict';
|
3
|
+
var __slice = [].slice;
|
4
|
+
|
5
|
+
define(function() {
|
6
|
+
var activate, add, addCSSClassName, cssClassName, deactivate, debug, exports, features, get, isActive, logPrefix, push, removeCSSClassName, reset, showLog, state, subscribe, subscribers, update, urlValues, _buildSubscriber, _log, _notifySubscriberOnActivate, _notifySubscribersOnActivate, _notifySubscribersOnDeactivate, _urlValueMatches, _urlValues;
|
7
|
+
features = {};
|
8
|
+
subscribers = {};
|
9
|
+
showLog = false;
|
10
|
+
logPrefix = '[PinballWizard]';
|
11
|
+
_log = function() {
|
12
|
+
var args, message;
|
13
|
+
message = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
14
|
+
if (showLog && window.console && window.console.log) {
|
15
|
+
console.log.apply(console, ["" + logPrefix + " " + message].concat(__slice.call(args)));
|
16
|
+
}
|
17
|
+
};
|
18
|
+
_notifySubscribersOnActivate = function(name) {
|
19
|
+
var subscriber, _i, _len, _ref, _results;
|
20
|
+
if (subscribers[name] == null) {
|
21
|
+
subscribers[name] = [];
|
22
|
+
}
|
23
|
+
_ref = subscribers[name];
|
24
|
+
_results = [];
|
25
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
26
|
+
subscriber = _ref[_i];
|
27
|
+
_results.push(_notifySubscriberOnActivate(subscriber, name));
|
28
|
+
}
|
29
|
+
return _results;
|
30
|
+
};
|
31
|
+
_notifySubscriberOnActivate = function(subscriber, name) {
|
32
|
+
_log('Notify subscriber that %s is active', name);
|
33
|
+
return subscriber.onActivate();
|
34
|
+
};
|
35
|
+
_notifySubscribersOnDeactivate = function(name) {
|
36
|
+
var subscriber, _i, _len, _ref, _results;
|
37
|
+
if (subscribers[name] == null) {
|
38
|
+
subscribers[name] = [];
|
39
|
+
}
|
40
|
+
_ref = subscribers[name];
|
41
|
+
_results = [];
|
42
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
43
|
+
subscriber = _ref[_i];
|
44
|
+
_results.push(subscriber.onDeactivate());
|
45
|
+
}
|
46
|
+
return _results;
|
47
|
+
};
|
48
|
+
_urlValueMatches = function(value) {
|
49
|
+
var v, _i, _len, _ref;
|
50
|
+
_ref = _urlValues();
|
51
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
52
|
+
v = _ref[_i];
|
53
|
+
if (value === v) {
|
54
|
+
return true;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return false;
|
58
|
+
};
|
59
|
+
_urlValues = function(search) {
|
60
|
+
var key, pair, pairs, value, _i, _len, _ref;
|
61
|
+
if (search == null) {
|
62
|
+
search = window.location.search;
|
63
|
+
}
|
64
|
+
pairs = search.substr(1).split('&');
|
65
|
+
for (_i = 0, _len = pairs.length; _i < _len; _i++) {
|
66
|
+
pair = pairs[_i];
|
67
|
+
_ref = pair.split('='), key = _ref[0], value = _ref[1];
|
68
|
+
if (key === 'pinball' && (value != null)) {
|
69
|
+
return value.split(',');
|
70
|
+
}
|
71
|
+
}
|
72
|
+
return [];
|
73
|
+
};
|
74
|
+
urlValues = _urlValues();
|
75
|
+
cssClassName = function(name, prefix) {
|
76
|
+
if (prefix == null) {
|
77
|
+
prefix = 'use-';
|
78
|
+
}
|
79
|
+
return prefix + name.split('_').join('-');
|
80
|
+
};
|
81
|
+
addCSSClassName = function(name, ele) {
|
82
|
+
var cN;
|
83
|
+
if (ele == null) {
|
84
|
+
ele = document.documentElement;
|
85
|
+
}
|
86
|
+
cN = cssClassName(name);
|
87
|
+
if (ele.className.indexOf(cN) < 0) {
|
88
|
+
return ele.className += ' ' + cN;
|
89
|
+
}
|
90
|
+
};
|
91
|
+
removeCSSClassName = function(name, ele) {
|
92
|
+
var cN;
|
93
|
+
if (ele == null) {
|
94
|
+
ele = document.documentElement;
|
95
|
+
}
|
96
|
+
cN = cssClassName(name);
|
97
|
+
if (ele.className.indexOf(cN) >= 0) {
|
98
|
+
return ele.className = ele.className.replace(cN, '');
|
99
|
+
}
|
100
|
+
};
|
101
|
+
add = function(list) {
|
102
|
+
var name, state, _results;
|
103
|
+
_results = [];
|
104
|
+
for (name in list) {
|
105
|
+
state = list[name];
|
106
|
+
features[name] = state;
|
107
|
+
_log("Added %s: %s.", name, state);
|
108
|
+
if (isActive(name)) {
|
109
|
+
_results.push(activate(name, "automatic. added as '" + state + "'"));
|
110
|
+
} else if (_urlValueMatches(name, urlValues)) {
|
111
|
+
_results.push(activate(name, 'URL'));
|
112
|
+
} else {
|
113
|
+
_results.push(void 0);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
return _results;
|
117
|
+
};
|
118
|
+
get = function(name) {
|
119
|
+
return features[name];
|
120
|
+
};
|
121
|
+
update = function(name, state) {
|
122
|
+
return features[name] = state;
|
123
|
+
};
|
124
|
+
activate = function(name, sourceName) {
|
125
|
+
var source, state;
|
126
|
+
if (sourceName == null) {
|
127
|
+
sourceName = null;
|
128
|
+
}
|
129
|
+
state = get(name);
|
130
|
+
source = sourceName != null ? " (source: " + sourceName + ")" : '';
|
131
|
+
switch (state) {
|
132
|
+
case void 0:
|
133
|
+
return _log("Attempted to activate %s, but it was not found%s.", name, source);
|
134
|
+
case 'inactive':
|
135
|
+
_log("Activate %s%s.", name, source);
|
136
|
+
update(name, 'active');
|
137
|
+
addCSSClassName(name);
|
138
|
+
return _notifySubscribersOnActivate(name);
|
139
|
+
case 'active':
|
140
|
+
return _log("Attempted to activate %s, but it is already active%s.", name, source);
|
141
|
+
default:
|
142
|
+
return _log("Attempted to activate %s, but it is %s%s.", name, state, source);
|
143
|
+
}
|
144
|
+
};
|
145
|
+
deactivate = function(name, source) {
|
146
|
+
var state;
|
147
|
+
if (source == null) {
|
148
|
+
source = null;
|
149
|
+
}
|
150
|
+
state = get(name);
|
151
|
+
source = typeof sourceName !== "undefined" && sourceName !== null ? " (source: " + sourceName + ")" : '';
|
152
|
+
switch (state) {
|
153
|
+
case void 0:
|
154
|
+
return _log("Attempted to deactivate %s, but it was not found%s.", name, source);
|
155
|
+
case 'active':
|
156
|
+
_log("Dectivate %s%s.", name, source);
|
157
|
+
update(name, 'inactive');
|
158
|
+
removeCSSClassName(name);
|
159
|
+
return _notifySubscribersOnDeactivate(name);
|
160
|
+
default:
|
161
|
+
return _log("Attempted to deactivate %s, but it is %s%s.", name, state, source);
|
162
|
+
}
|
163
|
+
};
|
164
|
+
isActive = function(name) {
|
165
|
+
return get(name) === 'active';
|
166
|
+
};
|
167
|
+
_buildSubscriber = function(onActivate, onDeactivate) {
|
168
|
+
return {
|
169
|
+
onActivate: onActivate != null ? onActivate : function() {},
|
170
|
+
onDeactivate: onDeactivate != null ? onDeactivate : function() {}
|
171
|
+
};
|
172
|
+
};
|
173
|
+
subscribe = function(name, onActivate, onDeactivate) {
|
174
|
+
var subscriber;
|
175
|
+
_log('Added subscriber to %s', name);
|
176
|
+
subscriber = _buildSubscriber(onActivate, onDeactivate);
|
177
|
+
if (subscribers[name] == null) {
|
178
|
+
subscribers[name] = [];
|
179
|
+
}
|
180
|
+
subscribers[name].push(subscriber);
|
181
|
+
if (isActive(name)) {
|
182
|
+
return _notifySubscriberOnActivate(subscriber, name);
|
183
|
+
}
|
184
|
+
};
|
185
|
+
push = function(params) {
|
186
|
+
var method;
|
187
|
+
method = params.shift();
|
188
|
+
return this[method].apply(this, params);
|
189
|
+
};
|
190
|
+
state = function() {
|
191
|
+
return features;
|
192
|
+
};
|
193
|
+
reset = function() {
|
194
|
+
return features = {};
|
195
|
+
};
|
196
|
+
debug = function() {
|
197
|
+
return showLog = true;
|
198
|
+
};
|
199
|
+
exports = {
|
200
|
+
add: add,
|
201
|
+
get: get,
|
202
|
+
activate: activate,
|
203
|
+
deactivate: deactivate,
|
204
|
+
isActive: isActive,
|
205
|
+
subscribe: subscribe,
|
206
|
+
push: push,
|
207
|
+
state: state,
|
208
|
+
reset: reset,
|
209
|
+
debug: debug,
|
210
|
+
cssClassName: cssClassName,
|
211
|
+
addCSSClassName: addCSSClassName,
|
212
|
+
removeCSSClassName: removeCSSClassName,
|
213
|
+
_urlValues: _urlValues
|
214
|
+
};
|
215
|
+
if (typeof window !== "undefined" && window !== null ? window.pinball : void 0) {
|
216
|
+
if (_urlValueMatches('debug')) {
|
217
|
+
debug();
|
218
|
+
}
|
219
|
+
while (window.pinball.length) {
|
220
|
+
exports.push(window.pinball.shift());
|
221
|
+
}
|
222
|
+
window.pinball = exports;
|
223
|
+
}
|
224
|
+
return exports;
|
225
|
+
});
|
226
|
+
|
227
|
+
}).call(this);
|
data/gulpfile.js
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
var gulp = require('gulp');
|
4
|
+
var coffee = require('gulp-coffee')
|
5
|
+
var gutil = require('gulp-util')
|
6
|
+
var sourcemaps = require('gulp-sourcemaps')
|
7
|
+
var del = require('del');
|
8
|
+
|
9
|
+
gulp.task('clean-dist', function (cb) {
|
10
|
+
del('dist/', cb);
|
11
|
+
});
|
12
|
+
|
13
|
+
gulp.task('dist', ['clean-dist'], function() {
|
14
|
+
gulp.src('src/**/*.coffee')
|
15
|
+
.pipe(coffee().on('error', gutil.log))
|
16
|
+
.pipe(gulp.dest('dist/'));
|
17
|
+
});
|
18
|
+
|
19
|
+
gulp.task('coffee', function() {
|
20
|
+
gulp.src('src/**/*.coffee')
|
21
|
+
.pipe(sourcemaps.init())
|
22
|
+
.pipe(coffee().on('error', gutil.log))
|
23
|
+
.pipe(sourcemaps.write())
|
24
|
+
.pipe(gulp.dest('.tmp/dist/'));
|
25
|
+
});
|
26
|
+
|
27
|
+
gulp.task('coffee-spec', function() {
|
28
|
+
gulp.src('test/**/*.coffee')
|
29
|
+
.pipe(sourcemaps.init())
|
30
|
+
.pipe(coffee().on('error', gutil.log))
|
31
|
+
.pipe(sourcemaps.write())
|
32
|
+
.pipe(gulp.dest('.tmp/test/'));
|
33
|
+
});
|
34
|
+
|
35
|
+
gulp.task('build', ['coffee','coffee-spec','dist']);
|
36
|
+
|
37
|
+
gulp.task('default', ['build'], function () {
|
38
|
+
gulp.watch('src/**/*.coffee', ['coffee','dist']);
|
39
|
+
gulp.watch('test/**/*.coffee', ['coffee-spec']);
|
40
|
+
});
|
data/karma.conf.js
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
// Karma configuration
|
2
|
+
// Generated on Tue Jan 13 2015 13:14:05 GMT-0500 (EST)
|
3
|
+
|
4
|
+
module.exports = function(config) {
|
5
|
+
config.set({
|
6
|
+
|
7
|
+
// base path that will be used to resolve all patterns (eg. files, exclude)
|
8
|
+
basePath: '.tmp/',
|
9
|
+
|
10
|
+
// frameworks to use
|
11
|
+
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
12
|
+
frameworks: ['jasmine','requirejs'],
|
13
|
+
|
14
|
+
|
15
|
+
// list of files / patterns to load in the browser
|
16
|
+
files: [
|
17
|
+
{pattern: 'dist/**/*.js', included: false},
|
18
|
+
{pattern: 'test/spec/**/*_spec.js', included: false},
|
19
|
+
|
20
|
+
'test/test-main.js'
|
21
|
+
],
|
22
|
+
|
23
|
+
// list of files to exclude
|
24
|
+
exclude: [
|
25
|
+
],
|
26
|
+
|
27
|
+
|
28
|
+
// preprocess matching files before serving them to the browser
|
29
|
+
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
30
|
+
preprocessors: {
|
31
|
+
},
|
32
|
+
|
33
|
+
|
34
|
+
// test results reporter to use
|
35
|
+
// possible values: 'dots', 'progress'
|
36
|
+
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
37
|
+
reporters: ['progress'],
|
38
|
+
|
39
|
+
|
40
|
+
// web server port
|
41
|
+
port: 9876,
|
42
|
+
|
43
|
+
|
44
|
+
// enable / disable colors in the output (reporters and logs)
|
45
|
+
colors: true,
|
46
|
+
|
47
|
+
|
48
|
+
// level of logging
|
49
|
+
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
50
|
+
logLevel: config.LOG_INFO,
|
51
|
+
|
52
|
+
|
53
|
+
// enable / disable watching file and executing tests whenever any file changes
|
54
|
+
autoWatch: true,
|
55
|
+
|
56
|
+
|
57
|
+
// start these browsers
|
58
|
+
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
59
|
+
browsers: ['Chrome'],
|
60
|
+
|
61
|
+
|
62
|
+
// Continuous Integration mode
|
63
|
+
// if true, Karma captures browsers, runs the tests and exits
|
64
|
+
singleRun: false
|
65
|
+
});
|
66
|
+
};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module PinballWizard
|
2
|
+
def self.configuration
|
3
|
+
@configuration ||= Configuration.new
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.configure
|
7
|
+
yield(configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
class Configuration
|
11
|
+
attr_accessor :class_patterns
|
12
|
+
|
13
|
+
def initialize(class_patterns = {})
|
14
|
+
@class_patterns = class_patterns
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pinball_wizard/helpers/hash'
|
2
|
+
|
3
|
+
module PinballWizard
|
4
|
+
module DSL
|
5
|
+
def self.build(config = PinballWizard.configuration, &block)
|
6
|
+
builder = Builder.new(config)
|
7
|
+
builder.instance_eval(&block)
|
8
|
+
builder
|
9
|
+
end
|
10
|
+
|
11
|
+
class Builder
|
12
|
+
attr_reader :config
|
13
|
+
|
14
|
+
def initialize(config)
|
15
|
+
@config = config
|
16
|
+
end
|
17
|
+
|
18
|
+
def feature(name, *options)
|
19
|
+
options = Helpers::Hash.normalize_options(options)
|
20
|
+
feature = build_feature(name, options)
|
21
|
+
Registry.add(feature)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_feature(name, options)
|
27
|
+
build_from_class_pattern(name, options) || Feature.new(name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_from_class_pattern(name, options)
|
31
|
+
config.class_patterns.each_pair do |key, klass|
|
32
|
+
return klass.new(name, options) if options.keys.include?(key)
|
33
|
+
end
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|