bezel-app 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c2182514434b0eb19d341fb9ea1724aae0bbfd59
4
+ data.tar.gz: 019978d0a49e4acdf84fb2c28cddc052dc8ef04d
5
+ SHA512:
6
+ metadata.gz: ba1fa4d2d752a193874a38dd91e09e507a87e438a04d49e41ff7322277b0226aca41adec8c94164d9816729b15d28ffeb75bfa265ed9db0842b595ad163afa4f
7
+ data.tar.gz: 34be517b8c9bd2c94641cb38b8ffa374991be236bb2bbc01ca970055ae8370ba2b6d4a46b27c58a2aa7a7d347806b07a41a4a0bdcae3c1369653f0a703d7fc8f
data/.gitconfig ADDED
@@ -0,0 +1,2 @@
1
+ [core]
2
+ editor = atom --wait
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack', '~> 1.6.4'
4
+ gem 'byebug'
5
+ gem "rspec", "~> 3.1.0"
6
+ gem "activesupport", '~> 4.2'
7
+ gem 'thor'
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (4.2.7.1)
5
+ i18n (~> 0.7)
6
+ json (~> 1.7, >= 1.7.7)
7
+ minitest (~> 5.1)
8
+ thread_safe (~> 0.3, >= 0.3.4)
9
+ tzinfo (~> 1.1)
10
+ byebug (9.0.5)
11
+ diff-lcs (1.2.5)
12
+ i18n (0.7.0)
13
+ json (1.8.3)
14
+ minitest (5.9.0)
15
+ rack (1.6.4)
16
+ rspec (3.1.0)
17
+ rspec-core (~> 3.1.0)
18
+ rspec-expectations (~> 3.1.0)
19
+ rspec-mocks (~> 3.1.0)
20
+ rspec-core (3.1.7)
21
+ rspec-support (~> 3.1.0)
22
+ rspec-expectations (3.1.2)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.1.0)
25
+ rspec-mocks (3.1.3)
26
+ rspec-support (~> 3.1.0)
27
+ rspec-support (3.1.2)
28
+ thor (0.19.1)
29
+ thread_safe (0.3.5)
30
+ tzinfo (1.2.2)
31
+ thread_safe (~> 0.1)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ activesupport (~> 4.2)
38
+ byebug
39
+ rack (~> 1.6.4)
40
+ rspec (~> 3.1.0)
41
+ thor
42
+
43
+ BUNDLED WITH
44
+ 1.12.5
data/bezel-app.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'bezel-app'
8
+ spec.version = '0.0.1'
9
+ spec.authors = ['Keith Thompson']
10
+ spec.email = ['KeithM_Thompson@outlook.com']
11
+
12
+ spec.summary = %q(A simple ORM and MVC inspired by Rails.)
13
+ spec.description =
14
+ %q(Replicate much of the core functionality of rails.)
15
+ spec.homepage = 'http://github.com/keithm-thompson/Bezel'
16
+ spec.license = 'MIT'
17
+
18
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
19
+ # delete this section to allow pushing this gem to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
+ else
23
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ spec.executables = 'bezel-app'
28
+
29
+ spec.add_runtime_dependency 'thor', '~> 0.19'
30
+ spec.add_runtime_dependency 'pg', '~> 0.18'
31
+ spec.add_runtime_dependency 'activesupport', '~> 4.2', '>= 4.2.5.1'
32
+ spec.add_runtime_dependency 'pry', '~> 0.10.3'
33
+ spec.add_runtime_dependency 'rack', '~> 1.6', '>= 1.6.4'
34
+ spec.add_runtime_dependency 'fileutils', '~> 0.7'
35
+
36
+ spec.add_development_dependency 'bundler', '~> 1.11'
37
+ spec.add_development_dependency 'rake', '~> 10.0'
38
+ spec.add_development_dependency 'rspec', '~> 3.0'
39
+ end
data/bin/bezel-app ADDED
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+
6
+ class Generate < Thor
7
+ desc 'model <name>', 'generate a model with the specified name.'
8
+ def model(name)
9
+ m_name = name.capitalize
10
+
11
+ # Writes model file
12
+ File.open("./app/models/#{m_name.downcase}.rb", 'w') do |f|
13
+ f.write("class #{m_name} < Bezel::BezelrecordBase\n\n")
14
+ f.write("end\n")
15
+ f.write("#{m_name}.finalize!")
16
+ end
17
+ migration("Create#{m_name}")
18
+ puts "#{m_name} model created"
19
+ end
20
+
21
+ desc 'controller <name>', 'generate a controller with the specified name.'
22
+ def controller(name)
23
+ c_name = name.capitalize
24
+
25
+ # Writes controller file
26
+ File.open("./app/controllers/#{c_name.downcase}.rb", 'w') do |f|
27
+ f.write("class #{c_name}Controller < Bezel::ControllerBase\n\n")
28
+ f.write('end')
29
+ end
30
+
31
+ # Creates empty views directory
32
+ Dir.mkdir "./app/views/#{c_name.downcase}_controller"
33
+ puts "#{c_name} controller created"
34
+ end
35
+
36
+ desc 'migration <name>', 'generates an empty sql file with a filename of the specified <name> appended to a timestamp'
37
+ def migration(name)
38
+ # Create a timestamp
39
+ ts = Time.now.to_s.split(' ').take(2).join('').split('').map(&:to_i).join
40
+ require 'active_support/inflector'
41
+ filename = "#{ts}__#{name.underscore.downcase}"
42
+
43
+ # Create the migration file
44
+ File.open("./db/migrate/#{filename}.sql", 'w') do |f|
45
+ f.write "CREATE TABLE IF NOT EXISTS #{name} (\n"
46
+ f.write "\tid SERIAL PRIMARY KEY,\n"
47
+ f.write "\tname VARCHAR(255) NOT NULL"
48
+ f.write ');'
49
+ end
50
+ end
51
+ end
52
+
53
+ # Top-level command for manipulating the database file.
54
+ class Db < Thor
55
+ desc 'create', 'creates the DB'
56
+ def create
57
+ require_relative '../lib/db_connection'
58
+ Bezel::DBConnection.reset
59
+ puts 'db created!'
60
+ end
61
+
62
+ desc 'migrate', 'runs pending migrations'
63
+ def migrate
64
+ # Creates Version table if necessary,
65
+ # then runs needed migrations in order.
66
+ require_relative '../lib/db_connection'
67
+ Bezel::DBConnection.migrate
68
+ puts 'migrated!'
69
+ end
70
+
71
+ desc 'seed', 'seeds the DB'
72
+ def seed
73
+ require_relative '../lib/bezel'
74
+ Bezel::Seed.populate
75
+ puts 'db seeded!'
76
+ end
77
+
78
+ desc 'reset', 'resets the DB and seeds it'
79
+ def reset
80
+ create
81
+ migrate
82
+ seed
83
+ puts 'db reset!'
84
+ end
85
+ end
86
+
87
+ class CLI < Thor
88
+ register(Generate, 'generate', 'generate <command>', 'Generates a model or controller.')
89
+ register(Db, 'db', 'db <command>', 'Accesses commands for the DB.')
90
+
91
+ desc 'g', 'alias of generate subcommand'
92
+ subcommand 'g', Generate
93
+
94
+ desc 'server', 'starts the Bezel server'
95
+ def server
96
+ require_relative '../lib/bezel'
97
+ Bezel::ServerConnection.start
98
+ end
99
+
100
+ desc 'new', 'creates a new Bezel app'
101
+ def new(name)
102
+ Dir.mkdir "./#{name}"
103
+ Dir.mkdir "./#{name}/config"
104
+
105
+ File.open("./#{name}/config/database.yml", 'w') do |f|
106
+ f.write("database: #{name}")
107
+ end
108
+
109
+ Dir.mkdir "./#{name}/app"
110
+ Dir.mkdir "./#{name}/app/models"
111
+ Dir.mkdir "./#{name}/app/views"
112
+ Dir.mkdir "./#{name}/app/controllers"
113
+ File.open("./#{name}/app/controllers/application_controller.rb", 'w') do |f|
114
+ f.write File.read(File.expand_path('../../template/app/controllers/application_controller.rb', __FILE__))
115
+ end
116
+ File.open("./#{name}/config/routes.rb", 'w') do |f|
117
+ f.write File.read(File.expand_path('../../template/config/routes.rb', __FILE__))
118
+ end
119
+ Dir.mkdir "./#{name}/db"
120
+ Dir.mkdir "./#{name}/db/migrate"
121
+ File.open("./#{name}/db/seeds.rb", 'w') do |f|
122
+ f.write File.read(File.expand_path('../../template/db/seeds.rb', __FILE__))
123
+ end
124
+ File.open("./#{name}/Gemfile", 'w') do |f|
125
+ f.write File.read(File.expand_path('../../template/Gemfile', __FILE__))
126
+ end
127
+ end
128
+ end
129
+
130
+ CLI.start(ARGV)
data/lib/bezel.rb ADDED
@@ -0,0 +1,15 @@
1
+ module Bezel
2
+ end
3
+
4
+ require_relative 'bezelrecord_base/bezelrecord_base'
5
+ require_relative 'controller_base'
6
+
7
+ Dir.glob('./app/models/*.rb') { |file| require file }
8
+ Dir.glob('./app/controllers/*.rb') { |file| require file }
9
+
10
+ require './db/seeds'
11
+
12
+ require_relative 'db_connection'
13
+ require_relative 'router'
14
+ require_relative 'server_connection'
15
+ require_relative 'session'
@@ -0,0 +1,114 @@
1
+ require_relative 'searchable'
2
+ require 'active_support/inflector'
3
+
4
+ class AssocOptions
5
+ attr_accessor(
6
+ :foreign_key,
7
+ :class_name,
8
+ :primary_key
9
+ )
10
+
11
+ def model_class
12
+ @model_class = class_name.constantize
13
+ end
14
+
15
+ def table_name
16
+ @table_name = model_class.table_name
17
+ end
18
+ end
19
+
20
+ class BelongsToOptions < AssocOptions
21
+ def initialize(name, options = {})
22
+ @foreign_key = options[:foreign_key] || (name.to_s + "Id").underscore.to_sym
23
+ @primary_key = options[:primary_key] || :id
24
+ @class_name = options[:class_name] || name.to_s.camelcase
25
+ end
26
+ end
27
+
28
+ class HasManyOptions < AssocOptions
29
+ def initialize(name, self_class_name, options = {})
30
+
31
+ @foreign_key = options[:foreign_key] || (self_class_name.to_s + "Id").underscore.to_sym
32
+ @primary_key = options[:primary_key] || :id
33
+ @class_name = options[:class_name] || name.to_s.singularize.camelcase
34
+ end
35
+ end
36
+
37
+ module Associatable
38
+ def belongs_to(name, options = {})
39
+ options = BelongsToOptions.new(name, options)
40
+ @prior_options = assoc_options
41
+ @prior_options[name] = options
42
+
43
+ define_method(options.class_name.downcase.to_sym) do
44
+ foreign_key = send(options.foreign_key)
45
+ the_class = options.model_class
46
+ the_class.where(options.primary_key => foreign_key).first
47
+ end
48
+ end
49
+
50
+ def has_many(name, options = {})
51
+ options = HasManyOptions.new(name, self, options)
52
+ @prior_options = assoc_options
53
+ if @prior_options[name.to_s.singularize.to_sym].nil?
54
+ @prior_options[name.to_s.singularize.to_sym] = options
55
+ else
56
+ @prior_options[name.to_s.singularize.to_sym] << options
57
+ end
58
+ define_method(options.table_name.to_sym) do
59
+ primary_key = send(options.primary_key)
60
+ options.model_class.where(options.foreign_key => primary_key)
61
+ end
62
+ end
63
+
64
+ def assoc_options
65
+ @prior_options ||= {}
66
+ end
67
+
68
+ def has_one_through(name, through_name, source_name)
69
+
70
+ define_method(name) do
71
+ through_options = self.class.assoc_options[through_name]
72
+ source_options = through_options.model_class.assoc_options[source_name]
73
+ search_by = send(through_options.foreign_key)
74
+
75
+ results = DBConnection.execute(<<-SQL, search_by)
76
+ SELECT
77
+ #{source_options.table_name}.*
78
+ FROM
79
+ #{through_options.table_name}
80
+ JOIN
81
+ #{source_options.table_name} ON #{source_options.table_name}.#{source_options.primary_key.to_s} = #{through_options.table_name}.#{source_options.foreign_key.to_s}
82
+ WHERE
83
+ #{through_options.table_name}.#{through_options.primary_key} = ?
84
+ SQL
85
+ source_options.model_class.new(results.first)
86
+ end
87
+ end
88
+
89
+ def has_many_through(name, through_name, source_name)
90
+
91
+ define_method(name) do
92
+ through_options = self.class.assoc_options[through_name]
93
+ source_options = through_options.model_class.assoc_options[source_name.to_s.singularize.to_sym]
94
+ search_classes = through_options.model_class.where(through_options.foreign_key => send(source_options.primary_key))
95
+
96
+ search_by = []
97
+ search_classes.each do |classes|
98
+ search_by << classes.send(source_options.primary_key)
99
+ end
100
+
101
+ results = DBConnection.execute(<<-SQL, *search_by)
102
+ SELECT
103
+ #{source_options.table_name}.*
104
+ FROM
105
+ #{through_options.table_name}
106
+ JOIN
107
+ #{source_options.table_name} ON #{source_options.table_name}.#{source_options.foreign_key.to_s} = #{through_options.table_name}.#{through_options.primary_key.to_s}
108
+ WHERE
109
+ #{through_options.table_name}.#{through_options.primary_key} IN (#{Array.new(search_by.length,"?").join(", ")})
110
+ SQL
111
+ results.map{|result| source_options.model_class.new(result)}
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,122 @@
1
+ require 'active_support/inflector'
2
+ require_relative '../../../db/lib/db_connection'
3
+ require_relative 'associatable'
4
+ require_relative 'searchable'
5
+
6
+ class BezelrecordBase
7
+ extend Associatable
8
+ extend Searchable
9
+
10
+ def self.columns
11
+ unless @columns
12
+ temp_columns = DBConnection.execute2(<<-SQL)
13
+ SELECT
14
+ *
15
+ FROM
16
+ #{table_name}
17
+ SQL
18
+ @columns = temp_columns.first.map { |column| column.to_sym }
19
+ end
20
+ @columns
21
+ end
22
+
23
+ def self.finalize!
24
+ columns.each do |column|
25
+
26
+ define_method("#{column}") do
27
+ @attributes = self.attributes
28
+ @attributes[column]
29
+ end
30
+
31
+ define_method("#{column}=") do |value|
32
+ @attributes = self.attributes
33
+ @attributes[column] = value
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.table_name=(table_name)
39
+ @table_name = table_name
40
+ end
41
+
42
+ def self.table_name
43
+ @table_name || to_s.tableize
44
+ end
45
+
46
+ def self.all
47
+ results = DBConnection.execute(<<-SQL)
48
+ SELECT
49
+ #{table_name}.*
50
+ FROM
51
+ #{table_name}
52
+ SQL
53
+ parse_all(results)
54
+ end
55
+
56
+ def self.parse_all(results)
57
+ objects = results.map do |object|
58
+ self.new(object)
59
+ end
60
+ end
61
+
62
+ def self.find(id)
63
+ object = DBConnection.execute(<<-SQL, id)
64
+ SELECT
65
+ *
66
+ FROM
67
+ #{table_name}
68
+ WHERE
69
+ id = ?
70
+ LIMIT
71
+ 1
72
+ SQL
73
+ nil || object.map {|obj| self.new(obj)}.first
74
+ end
75
+
76
+ def initialize(params = {})
77
+ table_columns = self.class.columns
78
+
79
+ params.each do |key, value|
80
+ raise "unknown attribute '#{key}'" unless table_columns.include?(key.to_sym)
81
+ send("#{key}=",value)
82
+ end
83
+ end
84
+
85
+ def attributes
86
+ @attributes = @attributes || {}
87
+ end
88
+
89
+ def attribute_values
90
+ table_cols = self.class.columns
91
+ table_cols
92
+ table_cols.map{ |col| self.send("#{col}")}
93
+ end
94
+
95
+ def insert
96
+ columns = self.class.columns
97
+
98
+ DBConnection.execute(<<-SQL, *attribute_values)
99
+ INSERT INTO
100
+ #{self.class.table_name} (#{columns.join(", ")})
101
+ VALUES
102
+ (#{Array.new(columns.length,"?").join(", ")})
103
+ SQL
104
+ self.send(:id=,DBConnection.last_insert_row_id)
105
+ end
106
+
107
+ def update
108
+ DBConnection.execute(<<-SQL,*attribute_values[1..-1], attribute_values.first)
109
+ UPDATE
110
+ #{self.class.table_name}
111
+ SET
112
+ #{self.class.columns[1..-1].map{|col| "#{col} = ?"}.join(", ")}
113
+ WHERE
114
+ id = ?
115
+ SQL
116
+
117
+ end
118
+
119
+ def save
120
+ id.nil? ? insert : update
121
+ end
122
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'db_connection'
2
+
3
+ module Searchable
4
+ def where(params)
5
+ where_line = params.keys.map{|key| "#{key} = ?"}
6
+ results = DBConnection.execute(<<-SQL, *params.values)
7
+ SELECT
8
+ *
9
+ FROM
10
+ #{table_name}
11
+ WHERE
12
+ #{where_line.join(" AND ")}
13
+ SQL
14
+ parse_all(results)
15
+ end
16
+
17
+
18
+ end
@@ -0,0 +1,78 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'erb'
4
+ require_relative './session'
5
+ require_relative './flash'
6
+
7
+ class ControllerBase
8
+ attr_reader :req, :res, :params, :flash
9
+
10
+ def self.protect_from_forgery
11
+ @@csrf_auth = true
12
+ end
13
+
14
+ def initialize(req, res, route_params = {})
15
+ @req = req
16
+ @res = res
17
+ @params = req.params.merge(route_params)
18
+ @flash = Flash.new(req)
19
+ @params['authenticity_token'] ||= SecureRandom.base64
20
+ end
21
+
22
+ def form_authenticity_token
23
+ @res.set_cookie('authenticity_token',@params['authenticity_token'])
24
+ @params['authenticity_token']
25
+ end
26
+
27
+ def check_authenticity_token(token = "")
28
+ @params['authenticity_token'] == token
29
+ end
30
+
31
+
32
+ def already_built_response?
33
+ !!@already_built_response
34
+ end
35
+
36
+
37
+ def redirect_to(url)
38
+ raise 'You cannot call render more than once' if already_built_response?
39
+ @res.status = 302
40
+ @res['Location'] = url
41
+ @already_built_response = true
42
+
43
+ session.store_session(@res)
44
+ end
45
+
46
+ def render_content(content, content_type)
47
+ raise 'You cannot call render more than once' if already_built_response?
48
+ @res['Content-Type'] = content_type
49
+ @res.write(content)
50
+ @already_built_response = true
51
+
52
+ session.store_session(@res)
53
+ end
54
+
55
+ def render(template_name)
56
+ file_name = "views/"
57
+ file_name += "#{self.class.to_s.underscore}/"
58
+ file_name += "#{template_name}.html.erb"
59
+ content = ERB.new(File.read(file_name)).result(binding)
60
+
61
+ render_content(content, "text/html")
62
+ end
63
+
64
+ def session
65
+ @session ||= Session.new(@req)
66
+ end
67
+
68
+ def invoke_action(name)
69
+ if @@csrf_auth && @req.request_method != "GET"
70
+ unless check_authenticity_token(@req.cookies['authenticity_token'])
71
+ raise "Invalid authenticity token"
72
+ end
73
+ end
74
+
75
+ send(name)
76
+ render(name) unless already_built_response?
77
+ end
78
+ end
@@ -0,0 +1,117 @@
1
+ require 'pg'
2
+ require 'yaml'
3
+
4
+ PRINT_QUERIES = ENV['PRINT_QUERIES'] == 'true'
5
+ MIGRATIONS = Dir.glob('./db/migrate/*.sql').to_a
6
+
7
+ module Bezel
8
+ class DBConnection
9
+ def self.app_name
10
+ YAML.load_file(Dir.pwd + '/config/database.yml')['database']
11
+ end
12
+
13
+ def self.add_to_version(file)
14
+ name = parse_migration_file(file)
15
+ execute(<<-SQL, [name])
16
+ INSERT INTO
17
+ version (name)
18
+ VALUES
19
+ ($1);
20
+ SQL
21
+ end
22
+
23
+ def self.columns(table_name)
24
+ columns = instance.exec(<<-SQL)
25
+ SELECT
26
+ attname
27
+ FROM
28
+ pg_attribute
29
+ WHERE
30
+ attrelid = '#{table_name}'::regclass AND
31
+ attnum > 0 AND
32
+ NOT attisdropped
33
+ SQL
34
+
35
+ columns.map { |col| col['attname'].to_sym }
36
+ end
37
+
38
+ def self.ensure_version_table
39
+ table = nil
40
+
41
+ if table.nil?
42
+ execute(<<-SQL)
43
+ CREATE TABLE IF NOT EXISTS version (
44
+ id SERIAL PRIMARY KEY,
45
+ name VARCHAR(255) NOT NULL
46
+ );
47
+ SQL
48
+ end
49
+ end
50
+
51
+ def self.execute(*args)
52
+ print_query(*args)
53
+ instance.exec(*args)
54
+ end
55
+
56
+ def self.instance
57
+ open if @db.nil?
58
+
59
+ @db
60
+ end
61
+
62
+ def self.migrate
63
+ ensure_version_table
64
+ to_migrate = MIGRATIONS.reject { |file| migrated?(file) }
65
+ to_migrate.each do |file|
66
+ add_to_version(file)
67
+ `psql -d #{app_name} -a -f #{file}`
68
+ end
69
+ end
70
+
71
+ def self.migrated?(file)
72
+ name = parse_migration_file(file)
73
+ result = execute(<<-SQL, [name])
74
+ SELECT
75
+ *
76
+ FROM
77
+ version
78
+ WHERE
79
+ name = $1;
80
+ SQL
81
+ !!result.first
82
+ end
83
+
84
+ def self.parse_migration_file(file)
85
+ filename = File.basename(file).split('.').first
86
+ u_idx = filename.index('_')
87
+ filename[0..u_idx - 1]
88
+ end
89
+
90
+ def self.print_query(query, *interpolation_args)
91
+ return unless PRINT_QUERIES
92
+
93
+ puts '--------------------'
94
+ puts query
95
+ unless interpolation_args.empty?
96
+ puts "interpolate: #{interpolation_args.inspect}"
97
+ end
98
+ puts '--------------------'
99
+ end
100
+
101
+ def self.open
102
+ @db = PG::Connection.new(
103
+ dbname: app_name,
104
+ port: 5432
105
+ )
106
+ end
107
+
108
+ def self.reset
109
+ commands = [
110
+ "dropdb #{app_name}",
111
+ "createdb #{app_name}"
112
+ ]
113
+
114
+ commands.each { |command| `#{command}` }
115
+ end
116
+ end
117
+ end
data/lib/flash.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ class Flash
4
+ def initialize(req)
5
+ if req.cookies['_bezel_flash']
6
+ @flash = JSON.parse(req.cookies['_bezel_flash'])
7
+ else
8
+ @flash = {}
9
+ end
10
+ @flash_now = {}
11
+ end
12
+
13
+ def []=(key,val)
14
+ @flash[key] = val
15
+ end
16
+
17
+ def [](key)
18
+ return @flash_now[key] if @flash_now[key]
19
+ @flash[key.to_s]
20
+ end
21
+
22
+ def store_flash(res)
23
+ res.set_cookie('_bezel_flash', value: @flash.to_json, path: '/')
24
+ end
25
+
26
+ def now
27
+ @flash_now
28
+ end
29
+ end
data/lib/router.rb ADDED
@@ -0,0 +1,60 @@
1
+ class Route
2
+ attr_reader :pattern, :http_method, :controller_class, :action_name
3
+
4
+ def initialize(pattern, http_method, controller_class, action_name)
5
+ @pattern = pattern
6
+ @http_method = http_method
7
+ @controller_class, @action_name = controller_class, action_name
8
+ end
9
+
10
+ def matches?(req)
11
+ pattern =~ req.path && http_method == req.request_method.downcase.to_sym
12
+ end
13
+
14
+ def run(req, res)
15
+ raise 'no action' unless matches?(req)
16
+ route_matches = @pattern.match(req.path)
17
+ route_params = {}
18
+ route_matches.names.each do |name|
19
+ route_params[name] = route_matches[name]
20
+ end
21
+ controller = controller_class.new(req,res,route_params)
22
+ controller.invoke_action(action_name)
23
+ end
24
+ end
25
+
26
+ class Router
27
+ attr_reader :routes
28
+
29
+ def initialize
30
+ @routes = []
31
+ end
32
+
33
+ def add_route(pattern, method, controller_class, action_name)
34
+ @routes << Route.new(pattern, method, controller_class, action_name)
35
+ end
36
+
37
+ def draw(&proc)
38
+ self.instance_eval(&proc)
39
+ end
40
+
41
+ [:get, :post, :put, :delete].each do |http_method|
42
+
43
+ define_method(http_method) do |pattern, controller_class, method|
44
+ add_route(pattern, http_method, controller_class, method)
45
+ end
46
+ end
47
+
48
+ def match(req)
49
+ @routes.each do |route|
50
+ return route if route.matches?(req)
51
+ end
52
+ nil
53
+ end
54
+
55
+ def run(req, res)
56
+ route = match(req)
57
+ return res.status = 404 unless route
58
+ route.run(req,res)
59
+ end
60
+ end
data/lib/session.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+
3
+ class Session
4
+ def initialize(req)
5
+ if req.cookies['_']
6
+ @cookie = JSON.parse(req.cookies['_bezel'])
7
+ else
8
+ @cookie = {}
9
+ end
10
+ end
11
+
12
+ def [](key)
13
+ @cookie[key]
14
+ end
15
+
16
+ def []=(key, val)
17
+ @cookie[key] = val
18
+ end
19
+
20
+ def store_session(res)
21
+ json_cookie = @cookie.to_json
22
+ res.set_cookie('_bezel', value: json_cookie, path: '/' )
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'erb'
2
+ class ShowExceptions
3
+ attr_reader :app
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ begin
11
+ app.call(env)
12
+ rescue Exception => e
13
+ render_exception(e)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def render_exception(e)
20
+ response = Rack::Response.new([], 500, 'Content_Type'=> 'text/html')
21
+ response.write(e.message)
22
+ response.finish
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ class StaticAssets
2
+ def initialize(app)
3
+ @app = app
4
+ end
5
+
6
+ def call(env)
7
+ file_path = "." + env['PATH_INFO']
8
+ res = Rack::Response.new
9
+ extension = /\.(\w*$)/.match(file_path)[1]
10
+ begin
11
+ res['Content-Type'] = set_content_type(extension)
12
+ content = File.read(file_path)
13
+ res.write(content)
14
+ rescue
15
+ res.status = 404
16
+ end
17
+
18
+ res.finish
19
+ end
20
+ end
21
+
22
+ private
23
+ def set_content_type(extension)
24
+ case extension
25
+ when "txt"
26
+ "text/plain"
27
+ when "jpg"
28
+ "image/jpeg"
29
+ when "zip"
30
+ "application/zip"
31
+ when "png"
32
+ "image/png"
33
+ else
34
+ raise 'extension not supported'
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < Bezel::ControllerBase
2
+ ApplicationController.protect_from_forgery
3
+ end
@@ -0,0 +1,9 @@
1
+ ROUTER = Bezel::Router.new
2
+ ROUTER.draw do
3
+ #Some sample routes:
4
+
5
+ # get Regexp.new("^/cats/new$"), CatsController, :new
6
+ # post Regexp.new("^/cats/create$"), CatsController, :create
7
+ # get Regexp.new("^/cats$"), CatsController, :index
8
+ # get Regexp.new("^/cats/(?<cat_id>\\d+)$"), CatsController, :show
9
+ end
@@ -0,0 +1,7 @@
1
+ module Bezel
2
+ class Seed
3
+ def self.populate
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ <h1>ALL THE CATS</h1>
2
+ <pre><%= @cats.to_s %></pre>
3
+ <a href="/cats/new">New cat!</a>
@@ -0,0 +1,11 @@
1
+ <form action="/cats" method="POST">
2
+ <label>Name
3
+ <input type="text" name="cat[name]" value="<%= @cat.name %>">
4
+ </label>
5
+
6
+ <label>Owner
7
+ <input type="text" name="cat[owner]" value="<%= @cat.owner %>">
8
+ </label>
9
+
10
+ <input type="submit">
11
+ </form>
@@ -0,0 +1,8 @@
1
+ <h1>ALL THE DOGS</h1>
2
+
3
+ <% if flash[:notice] %>
4
+ Notice: <%= flash[:notice] %>
5
+ <% end %>
6
+
7
+ <pre>Dog Data: <%= @dogs.to_s %></pre>
8
+ <a href="/dogs/new">New Dog!</a>
@@ -0,0 +1,19 @@
1
+ <% if flash[:errors] %>
2
+ <% flash[:errors].each do |error| %>
3
+ <%= error %>
4
+ <% end %>
5
+ <% end %>
6
+
7
+ <form action="/dogs" method="POST">
8
+ <label>Name
9
+ <input type="text" name="dog[name]" value="<%= @dog.name %>">
10
+ </label>
11
+ <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
12
+
13
+
14
+ <label>Owner
15
+ <input type="text" name="dog[owner]" value="<%= @dog.owner %>">
16
+ </label>
17
+
18
+ <input type="submit">
19
+ </form>
@@ -0,0 +1 @@
1
+ <%= link_to "all dogs", dogs_path %>
File without changes
@@ -0,0 +1 @@
1
+ <%= session["count"] %>
@@ -0,0 +1 @@
1
+ <%= (1..10).to_a.join(", ") %>
metadata ADDED
@@ -0,0 +1,214 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bezel-app
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Keith Thompson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.18'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.18'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.2'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 4.2.5.1
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '4.2'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 4.2.5.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: pry
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.10.3
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.10.3
75
+ - !ruby/object:Gem::Dependency
76
+ name: rack
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.6'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.6.4
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '1.6'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.6.4
95
+ - !ruby/object:Gem::Dependency
96
+ name: fileutils
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.7'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '0.7'
109
+ - !ruby/object:Gem::Dependency
110
+ name: bundler
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1.11'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1.11'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rake
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '10.0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '10.0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '3.0'
151
+ description: Replicate much of the core functionality of rails.
152
+ email:
153
+ - KeithM_Thompson@outlook.com
154
+ executables:
155
+ - bezel-app
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - ".byebug_history"
160
+ - ".gitconfig"
161
+ - ".gitignore"
162
+ - ".rspec"
163
+ - Gemfile
164
+ - Gemfile.lock
165
+ - bezel-app.gemspec
166
+ - bin/bezel-app
167
+ - lib/bezel.rb
168
+ - lib/bezelrecord_base/associatable.rb
169
+ - lib/bezelrecord_base/bezelrecord_base.rb
170
+ - lib/bezelrecord_base/searchable.rb
171
+ - lib/controller_base.rb
172
+ - lib/db_connection.rb
173
+ - lib/flash.rb
174
+ - lib/router.rb
175
+ - lib/session.rb
176
+ - lib/show_exceptions.rb
177
+ - lib/static_assets.rb
178
+ - template/app/controllers/application_controller.rb
179
+ - template/config/routes.rb
180
+ - template/db/seeds.rb
181
+ - views/cats_controller/index.html.erb
182
+ - views/cats_controller/new.html.erb
183
+ - views/dogs_controller/index.html.erb
184
+ - views/dogs_controller/new.html.erb
185
+ - views/dogs_controller/show.html.erb
186
+ - views/dummy_controller/index.html.erb
187
+ - views/my_controller/counting_show.html.erb
188
+ - views/my_controller/show.html.erb
189
+ homepage: http://github.com/keithm-thompson/Bezel
190
+ licenses:
191
+ - MIT
192
+ metadata:
193
+ allowed_push_host: https://rubygems.org
194
+ post_install_message:
195
+ rdoc_options: []
196
+ require_paths:
197
+ - lib
198
+ required_ruby_version: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ required_rubygems_version: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ requirements: []
209
+ rubyforge_project:
210
+ rubygems_version: 2.2.2
211
+ signing_key:
212
+ specification_version: 4
213
+ summary: A simple ORM and MVC inspired by Rails.
214
+ test_files: []