gameplan 0.0.1

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.
Files changed (35) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +16 -0
  4. data/README.md +3 -0
  5. data/Rakefile +3 -0
  6. data/bin/gameplan +7 -0
  7. data/gameplan.gemspec +22 -0
  8. data/lib/gameplan/application.rb +55 -0
  9. data/lib/gameplan/common_state.rb +41 -0
  10. data/lib/gameplan/describe.rb +11 -0
  11. data/lib/gameplan/endpoint.rb +9 -0
  12. data/lib/gameplan/flow.rb +39 -0
  13. data/lib/gameplan/frontend/public/css/application.css +6 -0
  14. data/lib/gameplan/frontend/public/css/bootstrap-responsive.css +808 -0
  15. data/lib/gameplan/frontend/public/css/bootstrap-responsive.min.css +9 -0
  16. data/lib/gameplan/frontend/public/css/bootstrap.css +4960 -0
  17. data/lib/gameplan/frontend/public/css/bootstrap.min.css +9 -0
  18. data/lib/gameplan/frontend/public/img/glyphicons-halflings-white.png +0 -0
  19. data/lib/gameplan/frontend/public/img/glyphicons-halflings.png +0 -0
  20. data/lib/gameplan/frontend/public/js/bootstrap.js +1824 -0
  21. data/lib/gameplan/frontend/public/js/bootstrap.min.js +6 -0
  22. data/lib/gameplan/frontend/views/app.erb +6 -0
  23. data/lib/gameplan/frontend/views/home.erb +6 -0
  24. data/lib/gameplan/frontend/views/layout/application.erb +76 -0
  25. data/lib/gameplan/frontend/views/state.erb +8 -0
  26. data/lib/gameplan/fuck_ruby.rb +25 -0
  27. data/lib/gameplan/pending_state.rb +20 -0
  28. data/lib/gameplan/site_generator.rb +44 -0
  29. data/lib/gameplan/state.rb +50 -0
  30. data/lib/gameplan/transitions.rb +20 -0
  31. data/lib/gameplan/user.rb +9 -0
  32. data/lib/gameplan/validation.rb +28 -0
  33. data/lib/gameplan/version.rb +3 -0
  34. data/lib/gameplan.rb +140 -0
  35. metadata +92 -0
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Bootstrap.js by @fat & @mdo
3
+ * Copyright 2012 Twitter, Inc.
4
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
5
+ */
6
+ !function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.hide)return c.hide();clearTimeout(this.timeout),c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var b=a(this),c=b.data("target")||b.attr("href"),d=/^#\w/.test(c)&&a(c);return d&&c.length&&[[d.position().top,c]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu")&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery);
@@ -0,0 +1,6 @@
1
+ <h1>Application <%=@app.pretty_name%></h1>
2
+ <ul>
3
+ <% @app.states.values.each do |state| %>
4
+ <li><a href="app-<%= @app.name %>-state-<%= state.name %>.html"><%= state.pretty_name %></a> - <%= state.description %></li>
5
+ <% end %>
6
+ </ul>
@@ -0,0 +1,6 @@
1
+ <h1>Applications</h1>
2
+ <ul>
3
+ <% @plan.apps.each do |name, app| %>
4
+ <li><a href="app-<%=name%>.html"><%=name%> - <%app.description%></li>
5
+ <% end %>
6
+ </ul>
@@ -0,0 +1,76 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Bootstrap, from Twitter</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <meta name="description" content="">
8
+ <meta name="author" content="">
9
+
10
+ <!-- Le styles -->
11
+ <link href="css/bootstrap.css" rel="stylesheet">
12
+ <style>
13
+ body {
14
+ padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
15
+ }
16
+ </style>
17
+ <link href="css/bootstrap-responsive.css" rel="stylesheet">
18
+
19
+ <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
20
+ <!--[if lt IE 9]>
21
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
22
+ <![endif]-->
23
+
24
+ <!-- Le fav and touch icons -->
25
+ <link rel="shortcut icon" href="/ico/favicon.ico">
26
+ <link rel="apple-touch-icon-precomposed" sizes="144x144" href="/ico/apple-touch-icon-144-precomposed.png">
27
+ <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/ico/apple-touch-icon-114-precomposed.png">
28
+ <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/ico/apple-touch-icon-72-precomposed.png">
29
+ <link rel="apple-touch-icon-precomposed" href="/ico/apple-touch-icon-57-precomposed.png">
30
+ </head>
31
+
32
+ <body>
33
+
34
+ <div class="navbar navbar-fixed-top">
35
+ <div class="navbar-inner">
36
+ <div class="container">
37
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
38
+ <span class="icon-bar"></span>
39
+ <span class="icon-bar"></span>
40
+ <span class="icon-bar"></span>
41
+ </a>
42
+ <a class="brand" href="#">Gameplan</a>
43
+ <div class="nav-collapse">
44
+ <ul class="nav">
45
+ <li class="active"><a href="index.html">Applications</a></li>
46
+ <!--<li><a href="#about">About</a></li>
47
+ <li><a href="#contact">Contact</a></li>-->
48
+ </ul>
49
+ </div><!--/.nav-collapse -->
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="container">
55
+ <%=@page%>
56
+ </div> <!-- /container -->
57
+
58
+ <!-- Le javascript
59
+ ================================================== -->
60
+ <!-- Placed at the end of the document so the pages load faster -->
61
+ <script src="js/jquery.js"></script>
62
+ <script src="js/bootstrap-transition.js"></script>
63
+ <script src="js/bootstrap-alert.js"></script>
64
+ <script src="js/bootstrap-modal.js"></script>
65
+ <script src="js/bootstrap-dropdown.js"></script>
66
+ <script src="js/bootstrap-scrollspy.js"></script>
67
+ <script src="js/bootstrap-tab.js"></script>
68
+ <script src="js/bootstrap-tooltip.js"></script>
69
+ <script src="js/bootstrap-popover.js"></script>
70
+ <script src="js/bootstrap-button.js"></script>
71
+ <script src="js/bootstrap-collapse.js"></script>
72
+ <script src="js/bootstrap-carousel.js"></script>
73
+ <script src="js/bootstrap-typeahead.js"></script>
74
+
75
+ </body>
76
+ </html>
@@ -0,0 +1,8 @@
1
+ <h1>Application <a href="app-<%=@app.name%>.html"><%=@app.pretty_name%></a></h1>
2
+ <h2><%= @state.pretty_name %> (<%= @state.name %>)</h2>
3
+ <p><%= @state.description %></p>
4
+ <ul>
5
+ <% @state.endpoints.each do |endpoint| %>
6
+ <li>Goto <a href="app-<%=@app.name%>-state-<%= endpoint.state %>.html"><%= endpoint.state %></a> <%= endpoint.description %></li>
7
+ <% end %>
8
+ </ul>
@@ -0,0 +1,25 @@
1
+ GameplanInstance = Gameplan.new
2
+
3
+ class String
4
+ # sorry ruby, had to do it.
5
+
6
+ def app(type, &blk)
7
+ GameplanInstance.app(self, type, &blk)
8
+ end
9
+
10
+ def common_state(name, &blk)
11
+ GameplanInstance.last_app.common_state(name, self, &blk)
12
+ end
13
+
14
+ def goto(state)
15
+ GameplanInstance.last_app.last_state.endpoint(state, self)
16
+ end
17
+
18
+ def state(name, &blk)
19
+ GameplanInstance.last_app.state(name, self, &blk)
20
+ end
21
+
22
+ def pending_state(name, &blk)
23
+ GameplanInstance.last_app.pending_state(name, self)
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ class Gameplan
2
+ class PendingState
3
+ attr_reader :name, :desc, :endpoints
4
+
5
+ def initialize(app, name, desc)
6
+ @app, @name, @desc, @endpoints = app, name, desc, []
7
+ end
8
+
9
+ def compile
10
+ end
11
+
12
+ def validate
13
+ add_warning "State #{@name} is pending"
14
+ end
15
+
16
+ def add_warning(str)
17
+ @app.add_warning(str)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ require "fileutils"
2
+ require "erb"
3
+ require 'ostruct'
4
+
5
+ class Gameplan
6
+ class SiteGenerator
7
+ def initialize(plan)
8
+ @plan = plan
9
+ @root = File.expand_path("../frontend", __FILE__)
10
+ @target = File.join(Dir.pwd, 'site')
11
+ @template = File.read(File.join(@root, "views/layout/application.erb"))
12
+ end
13
+
14
+ def generate
15
+ FileUtils.rm_rf(@target)
16
+ FileUtils.mkdir_p(@target)
17
+ # copy static assets
18
+ FileUtils.cp_r(File.join(@root, 'public/js'), @target)
19
+ FileUtils.cp_r(File.join(@root, 'public/img'), @target)
20
+ FileUtils.cp_r(File.join(@root, 'public/css'), @target)
21
+
22
+ generate_page('index', 'home')
23
+ @plan.apps.values.each do |app|
24
+ @app = app
25
+ generate_page("app-#{app.name}", 'app')
26
+ app.states.values.each do |state|
27
+ @state = state
28
+ generate_page("app-#{app.name}-state-#{state.name}", 'state')
29
+ end
30
+ end
31
+ end
32
+
33
+ def generate_page(out, name, locals = {})
34
+ template = File.join(@root, "views/layout/application.erb")
35
+ out_file = File.join(@target, "#{out}.html")
36
+ File.open(out_file, 'w') do |f|
37
+ in_file = File.join(@root, "views/#{name}.erb")
38
+ @page = ERB.new(File.read(in_file)).result(binding)
39
+ erb = ERB.new(File.read(template))
40
+ f << erb.result(binding)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ class Gameplan
2
+ class State
3
+ include Describe
4
+
5
+ attr_reader :endpoints, :name, :pretty_name
6
+
7
+ def initialize(app, name, pretty_name, &blk)
8
+ @app = app
9
+ @name = name
10
+ @pretty_name = pretty_name
11
+ @endpoints = []
12
+ @blk = blk
13
+ end
14
+
15
+ def compile
16
+ instance_eval(&@blk)
17
+ end
18
+
19
+ def use_common(name, mapping = {})
20
+ @app.common_states[name].endpoints.each do |ep|
21
+ endpoint(ep.state == :self ? self.name : mapping[ep.state] || ep.state, ep.description)
22
+ end
23
+ end
24
+
25
+ def endpoint(state, desc)
26
+ @endpoints << Endpoint.new(@app, state, desc)
27
+ end
28
+
29
+ def traverse(user, target_state, count, transitions)
30
+ return if count.zero?
31
+ transitions.emit if @name == target_state
32
+ @endpoints.each do |endpoint|
33
+ transitions.add(@name, endpoint.change_name) do
34
+ @app.states[endpoint.state_name].traverse(user, target_state, count - 1, transitions)
35
+ end
36
+ end
37
+ end
38
+
39
+ def validate
40
+ add_error "State #{@name} has no endpoints" if @endpoints.empty?
41
+ @endpoints.each do |ep|
42
+ add_error "Endpoint `#{ep.state}' (#{ep.description}) in #{@name} doesn't exist" unless @app.states[ep.state]
43
+ end
44
+ end
45
+
46
+ def add_error(str)
47
+ @app.add_error(str)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,20 @@
1
+ class Gameplan
2
+ class Transitions < Array
3
+ def initialize(yielder)
4
+ @yielder = yielder
5
+ end
6
+
7
+ def emit
8
+ @yielder << self.dup
9
+ end
10
+
11
+ def add(state_name, transition_name)
12
+ begin
13
+ self << [state_name, transition_name]
14
+ yield
15
+ ensure
16
+ pop
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ class Gameplan
2
+ class User
3
+ attr_reader :type
4
+
5
+ def initialize(type, *capabilities)
6
+ @type, @capabilities = type, capabilities
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ class Gameplan
2
+ module Validation
3
+ def add_warning(msg)
4
+ warnings << msg
5
+ end
6
+
7
+ def add_error(msg)
8
+ errors << msg
9
+ end
10
+
11
+ def errors
12
+ @errors ||= []
13
+ end
14
+
15
+ def warnings
16
+ @warnings ||= []
17
+ end
18
+
19
+ def reset_validation!
20
+ errors.clear
21
+ warnings.clear
22
+ end
23
+
24
+ def valid?
25
+ errors.empty? && warnings.empty?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ class Gameplan
2
+ VERSION = '0.0.1'
3
+ end
data/lib/gameplan.rb ADDED
@@ -0,0 +1,140 @@
1
+ require 'set'
2
+ require 'rainbow'
3
+
4
+ require 'gameplan/describe'
5
+ require 'gameplan/application'
6
+ require 'gameplan/endpoint'
7
+ require 'gameplan/flow'
8
+ require 'gameplan/state'
9
+ require 'gameplan/common_state'
10
+ require 'gameplan/pending_state'
11
+ require 'gameplan/user'
12
+ require 'gameplan/transitions'
13
+ require 'gameplan/validation'
14
+ require 'gameplan/site_generator'
15
+
16
+ class Gameplan
17
+ include Validation
18
+
19
+ attr_reader :apps, :flows, :last_app, :last_flow
20
+
21
+ def load(dir)
22
+ Dir[File.join(dir, "*.gplan")].each do |f|
23
+ instance_eval File.read(f), f, 1
24
+ end
25
+ compile
26
+ self
27
+ end
28
+
29
+ def compile
30
+ @apps.values.each(&:compile)
31
+ end
32
+
33
+ def initialize
34
+ @apps = {}
35
+ @flows = {}
36
+ @capabilities = []
37
+ end
38
+
39
+ def validate_and_report
40
+ validate
41
+ report
42
+ end
43
+
44
+ def generate
45
+ SiteGenerator.new(self).generate
46
+ end
47
+
48
+ def report
49
+ puts "RUNNING GAMEPLAN\n"
50
+ state_count = @apps.values.inject(0) { |s, a| s += a.states.size }
51
+ endpoint_count = @apps.values.inject(0) { |s, a| s += a.states.values.inject(0) {|ss, state| ss += state.endpoints.size } }
52
+ puts "You currently have #{@apps.size.to_s.foreground(:yellow)} apps with " <<
53
+ "#{state_count.to_s.foreground(:yellow)} states and " <<
54
+ "#{endpoint_count.to_s.foreground(:yellow)} endpoints defined."
55
+ puts "You currently have #{@flows.size.to_s.foreground(:yellow)} flows defined"
56
+ puts "#{@errors.size.to_s.foreground(:red)} errors, #{@warnings.size.to_s.foreground(:red)} warnings"
57
+ if valid?
58
+ puts "\nValid!".foreground(:green)
59
+ else
60
+ puts "\nThere were errors present:" unless errors.empty?
61
+ errors.each { |error| puts error }
62
+ puts "\nThere were warnings present:" unless warnings.empty?
63
+ warnings.each { |warning| puts warning }
64
+ end
65
+ end
66
+
67
+ def validate
68
+ reset_validation!
69
+ validate_apps
70
+ validate_flows
71
+ end
72
+
73
+ def validate_flows
74
+ validate_flow_traversability
75
+ end
76
+
77
+ def validate_states
78
+ validate_state_deadends
79
+ end
80
+
81
+ def validate_flow_traversability
82
+ with_all_users do |user|
83
+ @flows.keys.each do |name|
84
+ puts "VALIDATING #{name.inspect}"
85
+ test(name, user)# or add_error("Unable to traverse flow #{name}")
86
+ end
87
+ end
88
+ end
89
+
90
+ def validate_apps
91
+ @apps.values.each { |app| app.validate }
92
+ end
93
+
94
+ def capabilities(*capabilities)
95
+ @capabilities.concat(capabilities)
96
+ end
97
+
98
+ def app(name, type, &blk)
99
+ @last_app = @apps[type] = Application.new(self, name, type, &blk)
100
+ end
101
+
102
+ def flow(name, &blk)
103
+ @last_flow = flow = Flow.new(self, name, &blk)
104
+ @flows[name] = flow
105
+ flow
106
+ end
107
+
108
+ def travel(name, type)
109
+ user = User.new(type)
110
+ @flows[name].traverse(@apps[type], user)
111
+ end
112
+
113
+ def types
114
+ @apps.values.map(&:name)
115
+ end
116
+
117
+ def test(name, user)
118
+ types.each do |type|
119
+ @apps.values.select { |app| app.name == user.type }.all? do |app|
120
+ paths = @flows[name].traverse(app, user).to_a
121
+ add_error "Failed to traverse flow #{name}" if paths.empty?
122
+ end
123
+ end
124
+ end
125
+
126
+ private
127
+ def with_all_users
128
+ add_warning "No flows are currently defined" if @flows.empty?
129
+ add_warning "No apps are currently defined" if @apps.empty?
130
+ (0..@capabilities.size).each do |i|
131
+ @capabilities.combination(i).each do |combo|
132
+ types.each do |type|
133
+ yield User.new(type, *combo)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ require 'gameplan/fuck_ruby'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gameplan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Hull
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rainbow
16
+ requirement: &70164827246900 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70164827246900
25
+ description: Gotta plan your game dog.
26
+ email:
27
+ - joshbuddy@gmail.com
28
+ executables:
29
+ - gameplan
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - .gitignore
34
+ - Gemfile
35
+ - Gemfile.lock
36
+ - README.md
37
+ - Rakefile
38
+ - bin/gameplan
39
+ - gameplan.gemspec
40
+ - lib/gameplan.rb
41
+ - lib/gameplan/application.rb
42
+ - lib/gameplan/common_state.rb
43
+ - lib/gameplan/describe.rb
44
+ - lib/gameplan/endpoint.rb
45
+ - lib/gameplan/flow.rb
46
+ - lib/gameplan/frontend/public/css/application.css
47
+ - lib/gameplan/frontend/public/css/bootstrap-responsive.css
48
+ - lib/gameplan/frontend/public/css/bootstrap-responsive.min.css
49
+ - lib/gameplan/frontend/public/css/bootstrap.css
50
+ - lib/gameplan/frontend/public/css/bootstrap.min.css
51
+ - lib/gameplan/frontend/public/img/glyphicons-halflings-white.png
52
+ - lib/gameplan/frontend/public/img/glyphicons-halflings.png
53
+ - lib/gameplan/frontend/public/js/bootstrap.js
54
+ - lib/gameplan/frontend/public/js/bootstrap.min.js
55
+ - lib/gameplan/frontend/views/app.erb
56
+ - lib/gameplan/frontend/views/home.erb
57
+ - lib/gameplan/frontend/views/layout/application.erb
58
+ - lib/gameplan/frontend/views/state.erb
59
+ - lib/gameplan/fuck_ruby.rb
60
+ - lib/gameplan/pending_state.rb
61
+ - lib/gameplan/site_generator.rb
62
+ - lib/gameplan/state.rb
63
+ - lib/gameplan/transitions.rb
64
+ - lib/gameplan/user.rb
65
+ - lib/gameplan/validation.rb
66
+ - lib/gameplan/version.rb
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: gameplan
87
+ rubygems_version: 1.8.15
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Gotta plan your game dog
91
+ test_files: []
92
+ has_rdoc: