slick 0.16.3 → 0.17.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -8
  3. data/.slick +0 -0
  4. data/.travis.yml +3 -5
  5. data/LICENSE +20 -0
  6. data/README.md +3 -32
  7. data/Rakefile +1 -0
  8. data/config.rb +8 -0
  9. data/config.ru +4 -0
  10. data/exe/slick +8 -0
  11. data/lib/slick.rb +50 -3
  12. data/lib/slick/command.rb +29 -0
  13. data/lib/slick/commands/create_database.rb +9 -0
  14. data/lib/slick/commands/drop_database.rb +9 -0
  15. data/lib/slick/commands/init_database.rb +9 -0
  16. data/lib/slick/commands/list_commands.rb +14 -0
  17. data/lib/slick/commands/migrate_database.rb +9 -0
  18. data/lib/slick/commands/reset_database.rb +10 -0
  19. data/lib/slick/commands/start_console.rb +14 -0
  20. data/lib/slick/commands/start_server.rb +14 -0
  21. data/lib/slick/concern.rb +19 -0
  22. data/lib/slick/database.rb +168 -0
  23. data/lib/slick/database/abstract_row.rb +13 -0
  24. data/lib/slick/database/column.rb +64 -0
  25. data/lib/slick/database/migration.rb +36 -0
  26. data/lib/slick/database/migrator.rb +67 -0
  27. data/lib/slick/database/row.rb +127 -0
  28. data/lib/slick/database/table.rb +381 -0
  29. data/lib/slick/database/union.rb +86 -0
  30. data/lib/slick/helper.rb +24 -0
  31. data/lib/slick/helpers.rb +4 -0
  32. data/lib/slick/helpers/dir.rb +6 -0
  33. data/lib/slick/helpers/echo.rb +6 -0
  34. data/lib/slick/helpers/grab.rb +10 -0
  35. data/lib/slick/helpers/html_builder.rb +180 -0
  36. data/lib/slick/helpers/text_builder.rb +22 -0
  37. data/lib/slick/monkey_patches/html_escape.rb +8 -0
  38. data/lib/slick/monkey_patches/html_unescape.rb +8 -0
  39. data/lib/slick/monkey_patches/paramify.rb +11 -0
  40. data/lib/slick/monkey_patches/pluralize.rb +8 -0
  41. data/lib/slick/monkey_patches/require_all.rb +18 -0
  42. data/lib/slick/monkey_patches/singularize.rb +8 -0
  43. data/lib/slick/monkey_patches/url_encode.rb +8 -0
  44. data/lib/slick/monkey_patches/url_escape.rb +8 -0
  45. data/lib/slick/monkey_patches/url_unescape.rb +8 -0
  46. data/lib/slick/project.rb +53 -0
  47. data/lib/slick/project_watcher.rb +36 -0
  48. data/lib/slick/registry.rb +39 -0
  49. data/lib/slick/request.rb +6 -0
  50. data/lib/slick/resource_factories/config.rb +14 -0
  51. data/lib/slick/resource_factories/database.rb +6 -0
  52. data/lib/slick/resource_factories/database_schema_cache.rb +6 -0
  53. data/lib/slick/resource_factories/database_session_cache.rb +6 -0
  54. data/lib/slick/resource_factories/env.rb +14 -0
  55. data/lib/slick/resource_factories/environment.rb +6 -0
  56. data/lib/slick/resource_factories/file.rb +6 -0
  57. data/lib/slick/resource_factories/params.rb +6 -0
  58. data/lib/slick/resource_factories/project.rb +6 -0
  59. data/lib/slick/resource_factories/request.rb +6 -0
  60. data/lib/slick/resource_factories/response.rb +6 -0
  61. data/lib/slick/resource_factories/web.rb +11 -0
  62. data/lib/slick/resource_factory.rb +35 -0
  63. data/lib/slick/resource_provider.rb +51 -0
  64. data/lib/slick/response.rb +14 -0
  65. data/lib/slick/util.rb +72 -0
  66. data/lib/slick/util/inflections.rb +122 -0
  67. data/lib/slick/util/params_hash.rb +38 -0
  68. data/lib/slick/version.rb +1 -1
  69. data/lib/slick/web.rb +4 -0
  70. data/lib/slick/web/dir.rb +92 -0
  71. data/lib/slick/web/file.rb +66 -0
  72. data/lib/slick/web/file_interpreter.rb +24 -0
  73. data/lib/slick/web/file_interpreters/erb.rb +33 -0
  74. data/lib/slick/web/file_interpreters/js.rb +17 -0
  75. data/lib/slick/web/file_interpreters/rb.rb +14 -0
  76. data/lib/slick/web/file_interpreters/sass.rb +30 -0
  77. data/lib/slick/web/node.rb +35 -0
  78. data/lib/slick/workspace.rb +8 -0
  79. data/slick.gemspec +15 -4
  80. data/web/_layout.erb +13 -0
  81. data/web/index.erb +7 -0
  82. data/web/javascripts/index.js +2 -0
  83. data/web/stylesheets/index.scss +2 -0
  84. metadata +127 -11
  85. data/Gemfile.lock +0 -22
  86. data/bin/console +0 -14
  87. data/bin/setup +0 -8
@@ -0,0 +1,53 @@
1
+
2
+
3
+ class Slick::Project
4
+
5
+ attr_reader :root_path, :load_paths, :name, :lib_names
6
+
7
+ def initialize
8
+ @root_path = find_root_path(Dir.pwd)
9
+ @load_paths = $LOAD_PATH.map{|load_path| find_root_path(load_path) }.compact
10
+ if @root_path
11
+ @name = gem_name(@root_path)
12
+ @load_paths.unshift(@root_path) unless @load_paths.include?(@root_path)
13
+ end
14
+
15
+ @lib_names = @load_paths.map{|load_path| gem_name(load_path) }
16
+ end
17
+
18
+ def exist?
19
+ !@name.nil?
20
+ end
21
+
22
+ private
23
+
24
+ def find_file_path(path, pattern)
25
+ current_path = path
26
+ while true
27
+ Dir.open(current_path).each do |item|
28
+ candidate_file_path = "#{current_path}/#{item}"
29
+ return candidate_file_path if File.file?(candidate_file_path) && item.match(pattern)
30
+ end
31
+ if matches = current_path.match(/\A(.*)\/([^\/]+)\z/)
32
+ current_path = matches[1]
33
+ current_path = '/' if current_path == ''
34
+ else
35
+ break
36
+ end
37
+ end
38
+ nil
39
+ end
40
+
41
+ def find_root_path(path)
42
+ out = find_file_path(path, /\A\.slick\z/)
43
+ out.sub!(/\.slick\z/, '').sub!(/\A(.+)\/\z/, '\1') if out
44
+ out
45
+ end
46
+
47
+ def gem_name(path)
48
+ out = find_file_path(path, /\A[^\/]+\.gemspec\z/)
49
+ out.sub!(/\A.*\//, '').sub!(/\.gemspec\z/, '\1') if out
50
+ out
51
+ end
52
+
53
+ end
@@ -0,0 +1,36 @@
1
+
2
+ require "slick/helpers"
3
+
4
+ class Slick::ProjectWatcher
5
+
6
+ def self.watch
7
+ self.new.watch
8
+ end
9
+
10
+ include Slick::Helpers
11
+
12
+ def watch
13
+ last_modified_times = {}
14
+
15
+ while true
16
+ is_change = false
17
+
18
+ Dir.glob("#{project.root_path}/**/*").each do |file|
19
+ last_modified_time = File.mtime(file)
20
+ if last_modified_times[file] != last_modified_time
21
+ is_change = true
22
+ end
23
+ last_modified_times[file] = last_modified_time
24
+ end
25
+
26
+ if is_change
27
+ Process.kill('KILL', @child_process_pid) if @child_process_pid
28
+ @child_process_pid = Process.fork
29
+ break if !@child_process_pid
30
+
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ end
@@ -0,0 +1,39 @@
1
+
2
+ module Slick::Registry
3
+
4
+ attr_reader :name
5
+
6
+ def registered?
7
+ registered_classes.values.include? self
8
+ end
9
+
10
+ def registered_classes
11
+ @registered_classes ||= superclass.respond_to?(:registered_classes) ? superclass.registered_classes : {}
12
+ end
13
+
14
+ def register(name, *args, &block)
15
+ raise "Class has already been registered" if registered?
16
+ name = name.to_s
17
+ instance_eval{ @name = name }
18
+ registered_classes[name] = self
19
+ self
20
+ end
21
+
22
+ def for(name, options = {})
23
+ name = name.to_s
24
+ registered_classes[name] || begin
25
+ klass = Class.new(self)
26
+ if options.paramify.register_if_not_exists == 'true'
27
+ klass.register(name, options)
28
+ else
29
+ klass.instance_eval{ @name = name }
30
+ end
31
+ klass
32
+ end
33
+ end
34
+
35
+ def create(name, *args, &block)
36
+ self.for(name).new(*args, &block)
37
+ end
38
+
39
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "rack"
3
+
4
+ class Slick::Request < Rack::Request
5
+
6
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "config", :shared => true }.define_method "create" do
5
+ if project.exist?
6
+ config_file_path = "#{project.root_path}/config.rb"
7
+ Slick::Workspace.new.instance_eval(
8
+ File.read(config_file_path),
9
+ config_file_path
10
+ ).paramify
11
+ else
12
+ {}.paramify
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "database" }.define_method "create" do
5
+ Slick::Database.new(config.database)
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "database_schema_cache", :shared => true }.define_method "create" do
5
+ {}
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "database_session_cache" }.define_method "create" do
5
+ {}
6
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "env" }.define_method "create" do
5
+ {
6
+ "REQUEST_METHOD" => "GET",
7
+ "SCRIPT_NAME" => "",
8
+ "PATH_INFO" => "/",
9
+ "QUERY_STRING" => "",
10
+ "SERVER_NAME" => "localhost",
11
+ "SERVER_PORT" => "80",
12
+ "rack.input" => ""
13
+ }
14
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "environment", :shared => true }.define_method "create" do
5
+ ENV["RACK_ENV"] || "development"
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "file" }.define_method "create" do
5
+ web.find_file("/")
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "params" }.define_method "create" do
5
+ request.params.paramify
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "project", :shared => true }.define_method "create" do
5
+ Slick::Project.new
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "request" }.define_method "create" do
5
+ Slick::Request.new(env)
6
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "response" }.define_method "create" do
5
+ Slick::Response[200, {"Content-Type" => "text/html"}, []]
6
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require "slick/resource_factory"
3
+
4
+ Class.new(Slick::ResourceFactory){ register "web", :shared => true }.define_method "create" do
5
+ out = Slick::Web::Dir.new
6
+ project.load_paths.reverse.each do |load_path|
7
+ web_dir_path = "#{load_path}/web"
8
+ out.merge_dir(web_dir_path) if File.directory?(web_dir_path)
9
+ end
10
+ out
11
+ end
@@ -0,0 +1,35 @@
1
+
2
+ require "slick/registry"
3
+ require "slick/helper"
4
+ require "slick/helpers"
5
+
6
+
7
+ class Slick::ResourceFactory
8
+
9
+ class << self
10
+
11
+ include Slick::Registry
12
+
13
+ def register(name, options = {})
14
+ super(name)
15
+
16
+ @shared = options.paramify.shared == "true"
17
+
18
+ Class.new(Slick::Helper){ register name }.define_method "call" do
19
+ ::Slick.resource_provider[self.class.name]
20
+ end
21
+ end
22
+
23
+ def shared?
24
+ @shared
25
+ end
26
+
27
+ end
28
+
29
+ include Slick::Helpers
30
+
31
+ def create
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,51 @@
1
+
2
+
3
+ class Slick::ResourceProvider
4
+
5
+ attr_reader :shared_resources
6
+
7
+ def initialize
8
+ @shared_resources = {}
9
+ @mutex = Mutex.new
10
+ end
11
+
12
+ def thread_resources
13
+ Thread.current["SLICK_RESOURCES"] ||= {}
14
+ end
15
+
16
+ def [](name)
17
+ name = name.to_s
18
+
19
+ return thread_resources[name] if !thread_resources[name].nil?
20
+ return shared_resources[name] if !shared_resources[name].nil?
21
+
22
+ resource_factory = Slick::ResourceFactory.create(name)
23
+
24
+ if resource_factory.class.shared?
25
+ @mutex.synchronize { shared_resources[name] ||= resource_factory.create }
26
+ shared_resources[name]
27
+ else
28
+ thread_resources[name] = resource_factory.create
29
+ thread_resources[name]
30
+ end
31
+ end
32
+
33
+ def []=(name, value)
34
+ thread_resources[name.to_s] = value
35
+ self
36
+ end
37
+
38
+ def reset(shared = false, thread = true, &block)
39
+ previous_shared_resources = shared_resources
40
+ previous_thread_resources = thread_resources
41
+ @mutex.syncronize { @shared_resources = {} } if shared
42
+ Thread.current["SLICK_RESOURCES"] = {} if thread
43
+ if block
44
+ out = block.call
45
+ @mutex.synchronize { @shared_resources = previous_shared_resources } if shared
46
+ Thread.current["SLICK_RESOURCES"] = previous_thread_resources if thread
47
+ out
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require "rack"
3
+
4
+ class Slick::Response < Rack::Response
5
+
6
+ def to_s
7
+ body.join
8
+ end
9
+
10
+ def inspect
11
+ to_s
12
+ end
13
+
14
+ end
@@ -0,0 +1,72 @@
1
+
2
+ require 'cgi'
3
+
4
+ module Slick::Util
5
+
6
+ class << self
7
+
8
+ def pluralize(word)
9
+ word = word.to_s
10
+ Inflections.pluralize_rules.each do |rule|
11
+ pattern, replacement = rule
12
+ return word.sub(pattern, replacement) if word.match?(pattern)
13
+ end
14
+ end
15
+
16
+ def singularize(word)
17
+ word = word.to_s
18
+ Inflections.singularize_rules.each do |rule|
19
+ pattern, replacement = rule
20
+ return word.sub(pattern, replacement) if word.match?(pattern)
21
+ end
22
+ end
23
+
24
+ def html_escape(stringable)
25
+ CGI::escapeHTML(stringable.to_s)
26
+ end
27
+
28
+ def html_unescape(stringable)
29
+ CGI::unescapeHTML(stringable.to_s)
30
+ end
31
+
32
+ def url_escape(stringable)
33
+ CGI::escape(stringable.to_s)
34
+ end
35
+
36
+ def url_unescape(stringable)
37
+ CGI::unescape(stringable.to_s)
38
+ end
39
+
40
+ def paramify(hashable)
41
+ if hashable.kind_of?(Hash)
42
+ out = ParamsHash.new
43
+ hashable.each{|name, value| out[name] = paramify(value)}
44
+ out
45
+ elsif hashable.kind_of?(Array)
46
+ out = ParamsHash.new
47
+ hashable.each_with_index{|value, index| out[index] = paramify(value)}
48
+ out
49
+ else
50
+ return hashable
51
+ end
52
+ end
53
+
54
+ def url_encode(hashable, path = [], out = [])
55
+ hashable = paramify(hashable) if !hashable.kind_of?(ParamsHash)
56
+ if hashable.kind_of?(ParamsHash)
57
+ hashable.each do |name, value|
58
+ path.push(name)
59
+ url_encode(value, path, out)
60
+ path.pop
61
+ end
62
+ return out.join('&') if path.count == 0
63
+ elsif path.count == 0
64
+ return url_escape(hashable)
65
+ else
66
+ out << "#{url_escape(path.first)}#{path[1..path.length].map{|name| "[#{url_escape(name)}]"}.join}=#{url_escape(hashable)}"
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,122 @@
1
+
2
+ module Slick::Util::Inflections
3
+
4
+ instance_eval do
5
+ @pluralize_rules = []
6
+ @singularize_rules = []
7
+ end
8
+
9
+ class << self
10
+
11
+ attr_accessor :pluralize_rules
12
+ attr_accessor :singularize_rules
13
+
14
+ def plural(*args)
15
+ pluralize_rules.prepend(args)
16
+ end
17
+
18
+ def singular(*args)
19
+ singularize_rules.prepend(args)
20
+ end
21
+
22
+ def irregular(singular, plural)
23
+ s0 = singular[0]
24
+ srest = singular[1..-1]
25
+
26
+ p0 = plural[0]
27
+ prest = plural[1..-1]
28
+
29
+ if s0.upcase == p0.upcase
30
+ plural(/(#{s0})#{srest}$/i, '\1' + prest)
31
+ plural(/(#{p0})#{prest}$/i, '\1' + prest)
32
+
33
+ singular(/(#{s0})#{srest}$/i, '\1' + srest)
34
+ singular(/(#{p0})#{prest}$/i, '\1' + srest)
35
+ else
36
+ plural(/#{s0.upcase}(?i)#{srest}$/, p0.upcase + prest)
37
+ plural(/#{s0.downcase}(?i)#{srest}$/, p0.downcase + prest)
38
+ plural(/#{p0.upcase}(?i)#{prest}$/, p0.upcase + prest)
39
+ plural(/#{p0.downcase}(?i)#{prest}$/, p0.downcase + prest)
40
+
41
+ singular(/#{s0.upcase}(?i)#{srest}$/, s0.upcase + srest)
42
+ singular(/#{s0.downcase}(?i)#{srest}$/, s0.downcase + srest)
43
+ singular(/#{p0.upcase}(?i)#{prest}$/, s0.upcase + srest)
44
+ singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
45
+ end
46
+ end
47
+
48
+ def uncountable(singular_and_plural)
49
+ irregular(singular_and_plural, singular_and_plural)
50
+ end
51
+
52
+ end
53
+
54
+ plural(/$/, "s")
55
+ plural(/s$/i, "s")
56
+ plural(/^(ax|test)is$/i, '\1es')
57
+ plural(/(octop|vir)us$/i, '\1i')
58
+ plural(/(octop|vir)i$/i, '\1i')
59
+ plural(/(alias|status)$/i, '\1es')
60
+ plural(/(bu)s$/i, '\1ses')
61
+ plural(/(buffal|tomat)o$/i, '\1oes')
62
+ plural(/([ti])um$/i, '\1a')
63
+ plural(/([ti])a$/i, '\1a')
64
+ plural(/sis$/i, "ses")
65
+ plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
66
+ plural(/(hive)$/i, '\1s')
67
+ plural(/([^aeiouy]|qu)y$/i, '\1ies')
68
+ plural(/(x|ch|ss|sh)$/i, '\1es')
69
+ plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
70
+ plural(/^(m|l)ouse$/i, '\1ice')
71
+ plural(/^(m|l)ice$/i, '\1ice')
72
+ plural(/^(ox)$/i, '\1en')
73
+ plural(/^(oxen)$/i, '\1')
74
+ plural(/(quiz)$/i, '\1zes')
75
+
76
+ singular(/s$/i, "")
77
+ singular(/(ss)$/i, '\1')
78
+ singular(/(n)ews$/i, '\1ews')
79
+ singular(/([ti])a$/i, '\1um')
80
+ singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
81
+ singular(/(^analy)(sis|ses)$/i, '\1sis')
82
+ singular(/([^f])ves$/i, '\1fe')
83
+ singular(/(hive)s$/i, '\1')
84
+ singular(/(tive)s$/i, '\1')
85
+ singular(/([lr])ves$/i, '\1f')
86
+ singular(/([^aeiouy]|qu)ies$/i, '\1y')
87
+ singular(/(s)eries$/i, '\1eries')
88
+ singular(/(m)ovies$/i, '\1ovie')
89
+ singular(/(x|ch|ss|sh)es$/i, '\1')
90
+ singular(/^(m|l)ice$/i, '\1ouse')
91
+ singular(/(bus)(es)?$/i, '\1')
92
+ singular(/(o)es$/i, '\1')
93
+ singular(/(shoe)s$/i, '\1')
94
+ singular(/(cris|test)(is|es)$/i, '\1is')
95
+ singular(/^(a)x[ie]s$/i, '\1xis')
96
+ singular(/(octop|vir)(us|i)$/i, '\1us')
97
+ singular(/(alias|status)(es)?$/i, '\1')
98
+ singular(/^(ox)en/i, '\1')
99
+ singular(/(vert|ind)ices$/i, '\1ex')
100
+ singular(/(matr)ices$/i, '\1ix')
101
+ singular(/(quiz)zes$/i, '\1')
102
+ singular(/(database)s$/i, '\1')
103
+
104
+ irregular("person", "people")
105
+ irregular("man", "men")
106
+ irregular("child", "children")
107
+ irregular("sex", "sexes")
108
+ irregular("move", "moves")
109
+ irregular("zombie", "zombies")
110
+
111
+ uncountable "equipment"
112
+ uncountable "information"
113
+ uncountable "rice"
114
+ uncountable "money"
115
+ uncountable "species"
116
+ uncountable "series"
117
+ uncountable "fish"
118
+ uncountable "sheep"
119
+ uncountable "jeans"
120
+ uncountable "police"
121
+
122
+ end