shot_mvc 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []