shot_mvc 1.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.
data/LICENSE.md ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ Introduction
2
+ ------------
3
+
4
+ The Shot MVC implements a Model, View, Controller architecture on top of the base Shot Framework through a series of
5
+ Loaders and Routers. Additionally, the MVC gem allows you to use the `MVCApplication` class, which will automatically
6
+ set up all required MVC loaders and routers.
7
+
8
+ # Installation
9
+
10
+ ```bash
11
+ gem install shot_mvc
12
+ ```
13
+
14
+ # Usage Example
15
+
16
+ ```ruby
17
+ require 'shot_mvc'
18
+
19
+ app = MVCApplication.new
20
+
21
+ app.run do
22
+ app.on 'load' do |instance|
23
+ instance.get 'controller', 'Home'
24
+ end
25
+ end
26
+
27
+ app.start
28
+ ```
29
+
30
+ # Components
31
+
32
+ The Shot MVC is made up of a few different parts, which collectively make up a Model, View, Controller structure.
33
+
34
+ ## Model
35
+
36
+ At the time of writing, Models are not yet finished, but coming soon!
37
+
38
+ ## View
39
+
40
+ The View portion of the MVC is made up of **Elements** and **Templates**.
41
+
42
+ Elements correspond to an actual HTML element on the user's screen. Elements have an assigned jQuery selector, and can
43
+ trigger any jQuery function on the corresponding element on the page.
44
+
45
+ Elements are capable of rendering Templates, which are nothing more than an ERB file, with some special sauce.
46
+
47
+ ```ruby
48
+ body = get 'element', 'body'
49
+
50
+ body.html = 'Hello World'
51
+ body.jq 'css', ['background-color', 'red']
52
+
53
+ body.render 'some_template'
54
+ ```
55
+
56
+ ## Controllers
57
+
58
+ Controllers are just as you'd expect. All controllers inherit from the base `Controller` class, and they can be loaded
59
+ using the built in Loader.
60
+
61
+ ```ruby
62
+ home_controller = get 'controller', 'Home'
63
+ home_controller.index
64
+ ```
65
+
66
+
67
+ # License
68
+
69
+ Licensed under the MIT License. For full licensing information, please see LICENSE.md.
@@ -0,0 +1,30 @@
1
+ # What is this item?
2
+ #
3
+ # What does this item do?
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+ require 'shot_mvc'
10
+
11
+ class ViewController < Controller
12
+ def create(view)
13
+ contents = <<-eos
14
+ <br /><br />
15
+ <div class="container">
16
+ <div class="row">
17
+ <div class="span12">
18
+ <h1>#{view}</h1>
19
+ <p>This view is simply a placeholder for something amazing! You can edit the view here:</p>
20
+ <pre><code>application/views/#{view}.erb</code></pre>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ eos
25
+
26
+ File.write "application/views/#{view}.erb", contents
27
+
28
+ get('controller', 'Home').index
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ <br /><br />
2
+ <div class="container">
3
+ <div class="row">
4
+ <div class="span12">
5
+ <div class="hero-unit">
6
+ <h1>View Not Found</h1>
7
+ <p><pre><code><%=data[:requested_view]%></code></pre></p>
8
+ <p>Uh oh! It looks like you tried to render a view that doesn't exist yet.</p>
9
+
10
+ <p>
11
+ <a data-shot-click="GemRoot/application/controllers/view_controller.rb#create" data-shot-data="<%=data[:requested_view]%>" class="btn btn-primary btn-large">
12
+ Create View
13
+ </a>
14
+ </p>
15
+ </div>
16
+ </div>
17
+ </div>
18
+
19
+ <div class="row">
20
+ <div class="span12">
21
+ <h4>TemplateLoadException</h4>
22
+ <pre><code><%=data[:exception] %></code></pre>
23
+ <pre style='overflow-x: scroll'><code><%=data[:exception].backtrace.join('<br />') %></code></pre>
24
+ </div>
25
+ </div>
26
+ </div>
@@ -0,0 +1,41 @@
1
+ # Controller
2
+ #
3
+ # Implements a basic structure for a Shot MVC Controller
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+
10
+ class Controller
11
+ # Application instance to which the controller belongs
12
+ attr_accessor :app
13
+
14
+ # An array of actions which can not be called from a view
15
+ attr_accessor :view_private
16
+
17
+ # Instantiate the controller and keep track of the passed ApplicationInstance
18
+
19
+ def initialize(app)
20
+ @view_private = []
21
+ @app = app
22
+ end
23
+
24
+ # Adds an action to the list of private, non-view-callable actions
25
+ #
26
+ # == Attributes
27
+ #
28
+ # * +action+ - String name of a controller method
29
+
30
+ def add_private_action(action)
31
+ view_private.push action
32
+ end
33
+
34
+ # Utilize a Loader.
35
+ #
36
+ # Note:: This is a convenient access method for ApplicationInstance#get
37
+
38
+ def get(type, name)
39
+ @app.get type, name
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ # ControllerLoadException
2
+ #
3
+ # Raised if there was an issue while loading a controller.
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+
10
+ class ControllerLoadException < Exception
11
+ def initialize(message)
12
+ super(message)
13
+ end
14
+ end
@@ -0,0 +1,93 @@
1
+ # ControllerLoader
2
+ #
3
+ # Adds controller loading functionality to a Shot application. Will attempt to load controllers in the
4
+ # 'application/controllers' folder in the local working directory. If the file is not found, or an appropriate
5
+ # filesystem is not set up, a ControllerLoadException will be raised.
6
+ #
7
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
8
+ # Licensed under the MIT License. For full licensing information, please
9
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
10
+
11
+ require 'shot'
12
+ require_relative './controller_load_exception'
13
+
14
+ class String
15
+ # Converts a CamelCased string to a underscore_string
16
+ def underscore
17
+ self.gsub(/::/, '/').
18
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
19
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
20
+ tr("-", "_").
21
+ downcase
22
+ end
23
+
24
+ def camelize
25
+ parts = self.split '_'
26
+ parts.map! do |part| part.capitalize end
27
+ parts.join ''
28
+ end
29
+ end
30
+
31
+ class ControllerLoader < Loader
32
+ def initialize(client)
33
+ super(client)
34
+ @type = 'controller'
35
+ end
36
+
37
+ def get(controller)
38
+ if controller_exists? controller
39
+ if direct_path_to_controller? controller
40
+ load controller
41
+
42
+ controller_class_name = get_controller_class_from_path controller
43
+ controller_object = get_controller_object controller_class_name
44
+ controller_instance = controller_object.new @client
45
+
46
+ call_setup_method controller_object, controller_instance
47
+
48
+ controller_instance
49
+
50
+ else
51
+ load "application/controllers/#{controller.underscore}_controller.rb"
52
+
53
+ controller_class_name = get_controller_class controller
54
+ controller_object = get_controller_object controller_class_name
55
+ controller_instance = controller_object.new @client
56
+
57
+ call_setup_method controller_object, controller_instance
58
+
59
+ controller_instance
60
+ end
61
+ else
62
+ raise ControllerLoadException.new "Error loading controller #{controller}. Please verify that it exists at application/controllers/#{controller.underscore}.rb"
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def controller_exists?(controller)
69
+ File.exists? controller or File.exists? "application/controllers/#{controller.underscore}_controller.rb"
70
+ end
71
+
72
+ def direct_path_to_controller?(controller)
73
+ File.exists? controller
74
+ end
75
+
76
+ def call_setup_method(controller_object, controller_instance)
77
+ controller_instance.send 'setup' unless not controller_object.method_defined? :setup
78
+ end
79
+
80
+ def get_controller_object(class_name)
81
+ Object.const_get class_name
82
+ end
83
+
84
+ def get_controller_class(controller)
85
+ "#{controller}Controller"
86
+ end
87
+
88
+ def get_controller_class_from_path(controller)
89
+ last_part = controller.split('/')[-1]
90
+ last_part['.rb'] = ''
91
+ last_part.camelize
92
+ end
93
+ end
@@ -0,0 +1,38 @@
1
+ # ControllerRouter
2
+ #
3
+ # Routes incoming clients and handles their controller calls.
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+ require 'shot'
10
+ require_relative './controller_load_exception'
11
+
12
+ class ControllerRouter < Router
13
+ def initialize(client)
14
+ super(client)
15
+
16
+ client.on 'call_controller_action' do |data|
17
+ controller = data['controller']
18
+ if controller.include? 'GemRoot' then controller['GemRoot'] = gem_root end
19
+
20
+ action = data['action']
21
+ data = (data['data'] or nil)
22
+
23
+ controller = @client.get 'controller', controller
24
+
25
+ if controller.view_private.include? action then
26
+ raise ControllerLoadException.new "#{controller}##{action} is not view accessible."
27
+ end
28
+
29
+ if data then controller.send(action, data) else controller.send(action) end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def gem_root
36
+ Gem::Specification.find_by_name('shot_mvc').gem_dir
37
+ end
38
+ end
@@ -0,0 +1,52 @@
1
+ # Element
2
+ #
3
+ # Represents an element on the user's page, with a corresponding jQuery
4
+ # selector which can be used to call jQuery functions on the user's page.
5
+ #
6
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
7
+ # Licensed under the MIT License. For full licensing information, please
8
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
9
+
10
+
11
+ class Element
12
+ # jQuery Selector
13
+ attr_accessor :selector
14
+
15
+ # Associated ApplicationInstance
16
+ attr_accessor :app
17
+
18
+ def self.from_app_and_selector(app, selector)
19
+ element = Element.new selector
20
+ element.app = app
21
+ element
22
+ end
23
+
24
+ def initialize(selector)
25
+ @selector = selector
26
+ @app = nil
27
+ end
28
+
29
+ def jq(method, parameters = {})
30
+ unless app == nil
31
+ @app.emit 'jq', {
32
+ 'selector' => @selector,
33
+ 'method' => method,
34
+ 'parameters' => [parameters]
35
+ }
36
+ end
37
+ end
38
+
39
+ def html=(html)
40
+ self.jq 'html', [html]
41
+ end
42
+
43
+ def text=(text)
44
+ self.jq 'text', [text]
45
+ end
46
+
47
+ def render(template, data = nil)
48
+ template = @app.get 'template', template
49
+ template.data = data unless data == nil
50
+ self.html = template.render
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ # ElementLoader
2
+ #
3
+ # Allows the application to query the user's page from the server side in
4
+ # an API similiar to jQuery.
5
+ #
6
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
7
+ # Licensed under the MIT License. For full licensing information, please
8
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
9
+
10
+ require 'shot'
11
+ require_relative './element'
12
+
13
+ class ElementLoader < Loader
14
+ def initialize(client)
15
+ super(client)
16
+ @type = 'element'
17
+ end
18
+
19
+ def get(selector)
20
+ Element.from_app_and_selector @client, selector
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # What is this item?
2
+ #
3
+ # What does this item do?
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+ require 'shot'
10
+ require 'shot_mvc'
11
+
12
+ class MVCApplication < Application
13
+ def initialize(config = { :host => '127.0.0.1', :port => 8080 })
14
+ super(config)
15
+
16
+ add_router ControllerRouter
17
+ add_loader ControllerLoader
18
+ add_loader ElementLoader
19
+ add_loader TemplateLoader
20
+ add_loader ConfigurationLoader
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ # Template
2
+ #
3
+ # Wraps an ERB template in a container so data can be accessed properly.
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+ require 'erb'
10
+
11
+ class Template
12
+ # Absolute path to the ERB file
13
+ attr_accessor :template
14
+
15
+ # Data available to the ERB template
16
+ attr_accessor :data
17
+
18
+ def initialize(template_file)
19
+ @template = template_file
20
+ @data = {}
21
+ end
22
+
23
+ def render
24
+ template = ERB.new File.read @template
25
+ template.result binding
26
+ end
27
+
28
+ def data=(data)
29
+ @data.merge! data
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # TemplateLoadException
2
+ #
3
+ # Raised if there was an issue while loading a template.
4
+ #
5
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
6
+ # Licensed under the MIT License. For full licensing information, please
7
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
8
+
9
+
10
+ class TemplateLoadException < Exception
11
+ def initialize(message)
12
+ super(message)
13
+ end
14
+ end
@@ -0,0 +1,54 @@
1
+ # TemplateLoader
2
+ #
3
+ # Parses and loads ERB templates from the 'application/views' folder if
4
+ # it exists. If the folder does not exist, an exception will be raised.
5
+ #
6
+ # Shot Framework - Copyright (c) Jesse Aaron Dunlap <me@jessedunlap.me>
7
+ # Licensed under the MIT License. For full licensing information, please
8
+ # see LICENSE.md. http://github.com/JesseDunlap/shot/
9
+
10
+
11
+ require 'shot'
12
+ require 'erb'
13
+
14
+ require_relative './template'
15
+ require_relative './template_load_exception'
16
+
17
+ class TemplateLoader < Loader
18
+ def initialize(client)
19
+ super(client)
20
+ @type = 'template'
21
+ end
22
+
23
+ def get(name)
24
+ if template_exists? name
25
+ if full_path? name
26
+ Template.new name
27
+ else
28
+ Template.new "./application/views/#{name}.erb"
29
+ end
30
+ else
31
+ begin
32
+ raise TemplateLoadException.new "Could not load #{name}. Verify it exists at application/views/#{name}.erb"
33
+ rescue Exception => ex
34
+ template = Template.new "#{gem_root}/application/views/view_not_found.erb"
35
+ template.data = { :requested_view => name, :exception => ex }
36
+ return template
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def gem_root
44
+ Gem::Specification.find_by_name('shot_mvc').gem_dir
45
+ end
46
+
47
+ def full_path?(view_name)
48
+ File.exists? view_name
49
+ end
50
+
51
+ def template_exists?(view_name)
52
+ File.exists? view_name or File.exists? "application/views/#{view_name}.erb"
53
+ end
54
+ end
data/lib/shot_mvc.rb ADDED
@@ -0,0 +1,13 @@
1
+ require_relative './shot_mvc/controller_loader'
2
+ require_relative './shot_mvc/controller_load_exception'
3
+ require_relative './shot_mvc/controller_router'
4
+ require_relative './shot_mvc/controller'
5
+
6
+ require_relative './shot_mvc/element'
7
+ require_relative './shot_mvc/element_loader'
8
+
9
+ require_relative './shot_mvc/template_loader'
10
+ require_relative './shot_mvc/template'
11
+ require_relative './shot_mvc/template_load_exception'
12
+
13
+ require_relative './shot_mvc/mvc_application'
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shot_mvc
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jesse A. Dunlap
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: shot
16
+ requirement: !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: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: flexmock
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! 'Shot MVC allows for organization of your code in one of the most accepted
47
+ organization patterns: the MVC pattern. Provides supports for Models, Views, and
48
+ Controllers via a series of Routers and Loaders.'
49
+ email: me@jessedunlap.me
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/shot_mvc/controller.rb
55
+ - lib/shot_mvc/controller_loader.rb
56
+ - lib/shot_mvc/controller_load_exception.rb
57
+ - lib/shot_mvc/controller_router.rb
58
+ - lib/shot_mvc/element.rb
59
+ - lib/shot_mvc/element_loader.rb
60
+ - lib/shot_mvc/mvc_application.rb
61
+ - lib/shot_mvc/template.rb
62
+ - lib/shot_mvc/template_loader.rb
63
+ - lib/shot_mvc/template_load_exception.rb
64
+ - lib/shot_mvc.rb
65
+ - application/controllers/view_controller.rb
66
+ - application/views/view_not_found.erb
67
+ - LICENSE.md
68
+ - README.md
69
+ homepage: http://github.com/shot/
70
+ licenses:
71
+ - MIT
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.24
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: A Model, View, Controller (MVC) layer for the Shot Framework.
94
+ test_files: []