cubic 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a588fe718db876392ee7fb498a236d57045b32e1
4
+ data.tar.gz: 6223844472a330f8db725c9cdf8d8f9e44e5d51e
5
+ SHA512:
6
+ metadata.gz: 498d21669a59aebf9ec20cf52cb0bde1e1c2e0e9882fd92781e34e91bb52e802c584401d954e03320e065fff9103aae63ce24c02b0f0f78f411aace44f907ba7
7
+ data.tar.gz: ce24c69ee6c6ccb11902de0ff9f9eb23a3a53aaf1775158d02ceaf55066d1fdd3a714a4c8e513dce18172975ea80bdcce2f440aabf2a75c3be7b736d8cef3b3c
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'simplecov', :require => false, :group => :test
4
+ gemspec
@@ -0,0 +1,141 @@
1
+ # Cubic
2
+
3
+ Cubic is a small framework built with a focus on quickly creating applications through a neat, easily readable file that defines the basic structure of you app.
4
+
5
+ ## Sitemap (Generator)
6
+ ---
7
+ Cubic expects an application to be generated using a 'sitemap.rb' file. In general, you will place this file in the directory you would like to generate your application inside of, but you can also tell the Cubic to generate your application in a directory other than the one your sitemap currently resides in.
8
+ Within the sitemap.rb file, you will design a basic structure for your application,
9
+ then run that file with `ruby sitemap.rb` to generate it.
10
+
11
+ Here is an example of how such a file might look.
12
+
13
+ ```ruby
14
+ require 'cubic'
15
+
16
+ Cubic.sitemap do
17
+
18
+ config do
19
+ root_path File.expand_path('../', __FILE__)
20
+ html_type 'haml'
21
+ css_type 'css'
22
+ end
23
+
24
+ models do
25
+ design(:user, {email: :string, password_digest: :string}).add('# comment')
26
+ design(:post, {title: :string, content: :string})
27
+ end
28
+
29
+ controllers do
30
+ design(:home, actions: [:index])
31
+ design(:user, actions: [:new])
32
+ design(:session, actions: [:new])
33
+ design(:post, actions: [:new, :show, :edit])
34
+ end
35
+ end
36
+ ```
37
+
38
+ Let's quickly run through the blocks within the sitemap file.
39
+
40
+ ### Config
41
+ ```ruby
42
+ root_path File.expand_path('../', __FILE__)
43
+ ```
44
+ The root_path options tells the generator where you would like the application to be generated.
45
+ ```ruby
46
+ html_type 'haml'
47
+ css_type 'css'
48
+ ```
49
+ html_type and css_type tell the generator what template engine and preprocessor language you would files to be generated with.
50
+
51
+ ### Models
52
+ The models block does exactly what you think; it generates your models!
53
+ ```ruby
54
+ design(:post, {title: :string, content: :string})
55
+ ```
56
+ The first argument passed to the design
57
+ method tells the generator what you would like to name your model. The next argument, a hash,
58
+ is what will be passed to the migrations generator to create a database table for your model.
59
+
60
+ You can call `add()` on the design method to add code directly into the model to be generated.
61
+ Every argument is a new line, so something like:
62
+ ```ruby
63
+ add('one_to_many :authorships', 'many_to_many :books')
64
+ ```
65
+ generates the following
66
+
67
+ ```ruby
68
+ class SomeModel < Sequel::Model
69
+ one_to_many :authorships
70
+ many_to_many :books
71
+
72
+ end
73
+ ```
74
+
75
+ ### Controllers
76
+ ```ruby
77
+ design(:post, actions: [:new, :show, :edit])
78
+ ```
79
+ Generating a controller is similar to model. The first argument given is the name of the controller,
80
+ then you add your actions. The array associated with the action key is what will be used to create the necessary
81
+ views for your controller, but also the routes held within the controller. If that is kind of confusing,
82
+ the routing section below will explain.
83
+
84
+ That is about as deep as the generator goes for now, so lets move on.
85
+
86
+ ## Defining routes
87
+ ---
88
+ In a Cubic application, you define your routes within the controllers you have generated. You will notice each
89
+ controller has a namespace block, which all of your routes are defined within. It's okay
90
+ to create a route outside of this block, but to keep things easy to find, all routes are defined within it by default.
91
+
92
+ Below you can see an example of a normal Cubic controller. All http methods you see defined within the
93
+ namespace block are the ones given to you at the moment.
94
+
95
+ ```ruby
96
+ class HomeController < Cubic::CubicController
97
+ namespace 'home' do
98
+
99
+ get 'index' do
100
+ end
101
+
102
+ post 'index' do
103
+ end
104
+
105
+ put 'index' do
106
+ end
107
+
108
+ destroy 'index' do
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
114
+ Your route can have variables, which will be translated into a params hash.
115
+
116
+ ```ruby
117
+ get 'post/:title' do
118
+
119
+ end
120
+ ```
121
+
122
+ Then you could get the value passed in the url from within the controller or view
123
+ using the following:
124
+
125
+ ```ruby
126
+ params[:title]
127
+ ```
128
+
129
+ ## ORM
130
+ ---
131
+ Cubic uses Sequel as its ORM. To learn more about Sequel, read the documentation here: https://github.com/jeremyevans/sequel
132
+
133
+ ## Differences Between Environments
134
+ ---
135
+ As of now, Cubic's only major difference between Development and Production is the reloading of controller actions.
136
+ Because controller actions in Cubic are also routes, they must reloaded everytime a new call is made, which also means
137
+ any changes you make to a route also resets.
138
+
139
+ ## License
140
+ ---
141
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,29 @@
1
+ require 'rack'
2
+ require 'haml'
3
+ require 'erb'
4
+
5
+ require 'cubic/version'
6
+ require 'cubic/core_extensions'
7
+ require 'cubic/engine'
8
+ require 'cubic/application'
9
+ require 'cubic/render'
10
+ require 'cubic/generator'
11
+ require 'cubic/router'
12
+ require 'cubic/response'
13
+
14
+ require 'cubic/middleware/static'
15
+
16
+ # Cubic is a small framework built on the idea of quick generation using templates.
17
+ module Cubic
18
+ class << self
19
+
20
+ # First method to be called in the generation process.
21
+ def sitemap(&block)
22
+ Generator.run(&block)
23
+ end
24
+
25
+ def application
26
+ @app ||= Application
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,61 @@
1
+ require 'cubic/application/logable'
2
+ require 'cubic/application/configurator'
3
+ require 'cubic/application/controller'
4
+
5
+ module Cubic
6
+ # A cubic application inherits from the Application
7
+ # class, allowing it to change things such as
8
+ # configuration options.
9
+ class Application < Engine
10
+ class << self
11
+
12
+ # Requires all files from the generated application
13
+ # during startup.
14
+ def load_app
15
+ start_load if load_acceptable?
16
+ end
17
+
18
+ # Allows configuration options to be set within
19
+ # the config/application.rb file.
20
+ def config
21
+ Configurator
22
+ end
23
+
24
+ private
25
+
26
+ def load_acceptable?
27
+ !run_before? || development? ? has_run : false
28
+ end
29
+
30
+ def start_load
31
+ prime_app
32
+ Dir.glob(required_files).each { |f| load f }
33
+ end
34
+
35
+ def run_before?
36
+ @run_before ||= false
37
+ end
38
+
39
+ def has_run
40
+ @run_before = true
41
+ end
42
+
43
+ # Remove routes
44
+ def prime_app
45
+ Router.routes.clear
46
+ end
47
+
48
+ def development?
49
+ ENV['name'] == 'development'
50
+ end
51
+
52
+ def required_files
53
+ ctrls = File.join(config.root_dir, %w(app controllers *_controller.rb))
54
+ lib_files = File.join(config.root_dir, %w(lib ** *))
55
+ models = File.join(config.root_dir, %w(app models *.rb))
56
+
57
+ [ctrls, lib_files, models]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,16 @@
1
+ module Cubic
2
+ # Configuration stores details given during startup.
3
+ class Configurator
4
+ class << self
5
+ attr_accessor :template_engine
6
+
7
+ def design
8
+ yield self
9
+ end
10
+
11
+ def root_dir
12
+ APP_PATH
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,48 @@
1
+ module Cubic
2
+ # All classes generated by Cubic inherit from CubicController
3
+ class CubicController
4
+ extend Logable
5
+
6
+ class << self
7
+ attr_accessor :namespace
8
+
9
+ # Allows for namespacing within controllers who inherit
10
+ # from CubicController
11
+ def namespace(name, &b)
12
+ @namespace = name
13
+ b.call
14
+ ensure
15
+ @namespace = nil
16
+ end
17
+
18
+ def get(url, &block)
19
+ namespace_url(url) if @namespace
20
+ url[0] == '/' ? url : url.prepend('/')
21
+ route_setter('GET', url, block)
22
+ end
23
+
24
+ def post(url, &block)
25
+ namespace_url(url) if @namespace
26
+ route_setter('POST', url, block)
27
+ end
28
+
29
+ def put(url, &block)
30
+ namespace_url(url) if @namespace
31
+ route_setter('PUT', url, block)
32
+ end
33
+
34
+ def delete(url, &block)
35
+ namespace_url(url) if @namespace
36
+ route_setter('DELETE', url, block)
37
+ end
38
+
39
+ def route_setter(request_method, url, block)
40
+ Router.set_route(request_method, url, block)
41
+ end
42
+
43
+ def namespace_url(url)
44
+ url.prepend(@namespace + '/')
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ module Cubic
2
+ # Responsibe for logging information to the current environment log file.
3
+ module Logable
4
+
5
+ def log(message)
6
+ File.open(log_path, 'a') { |file| file.write(message) }
7
+ end
8
+
9
+ private
10
+
11
+ def log_path
12
+ File.join(APP_PATH, "log/#{env}.log")
13
+ end
14
+
15
+ def env
16
+ ENV['name'] || 'test'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ require 'cubic/core_extensions/string'
@@ -0,0 +1 @@
1
+ require 'cubic/core_extensions/string/parse'
@@ -0,0 +1,17 @@
1
+ module Cubic
2
+ module CoreExtensions
3
+ module Parse
4
+ def integer?
5
+ [
6
+ /^[-+]?[1-9]([0-9]*)?$/,
7
+ /^0[0-7]+$/,
8
+ /^0x[0-9A-Fa-f]+$/,
9
+ /^0b[01]+$/
10
+ ].each do |match_pattern|
11
+ return true if self =~ match_pattern
12
+ end
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,49 @@
1
+ require 'cubic/router'
2
+ require 'erb'
3
+
4
+ module Cubic
5
+ # Engine is what makes Cubic a Rack application.
6
+ class Engine
7
+
8
+ def self.call(env)
9
+ new(env).response.finish
10
+ end
11
+
12
+ def initialize(env)
13
+ @request = Rack::Request.new(env)
14
+ end
15
+
16
+ def response
17
+ Application.load_app
18
+ if search_routes
19
+ Response.new render
20
+ else
21
+ Response.new(status_404)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def status_404
28
+ { body: 'not found', status: 404 }
29
+ end
30
+
31
+ # Combines the params generated when checking routes
32
+ # with the params given by Rack::Request.
33
+ def merge_params
34
+ @request.params.merge(Router.params)
35
+ end
36
+
37
+ # Render a view.
38
+ def render
39
+ Render.new(merge_params, @content[:block]).template
40
+ end
41
+
42
+ # Checks if path given by Rack::Request matches
43
+ # any defined routes.
44
+ def search_routes
45
+ route = Router.search @request.request_method, @request.path
46
+ route ? @content = route : nil
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+ require_relative 'generators/config'
2
+ require_relative 'generators/base'
3
+ require_relative 'generators/controller'
4
+ require_relative 'generators/model'
5
+ require_relative 'generators/migrations'
6
+ require_relative 'generators/gemfile'
7
+ require_relative 'generators/view'
8
+ require_relative 'generators/app'
9
+
10
+ module Cubic
11
+ # The generator is what reads your sitemap file
12
+ # and generates the proper files.
13
+ module Generator
14
+ class << self
15
+
16
+ # Begins the generation process by running the block
17
+ # given from sitemap.rb file.
18
+ def run(&b)
19
+ @model = Model.new
20
+ @controller = Controller.new
21
+ @gemfile = Gemfile.new
22
+
23
+ instance_exec(&b)
24
+ App.create(@model, @controller, @gemfile)
25
+ end
26
+
27
+ private
28
+
29
+ def config(&b)
30
+ Config.instance_exec(&b)
31
+ end
32
+
33
+ def models(&b)
34
+ @model.instance_exec(&b)
35
+ end
36
+
37
+ def controllers(&b)
38
+ @controller.instance_exec(&b)
39
+ end
40
+ end
41
+ end
42
+ end