rail 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Guardfile +10 -0
  4. data/README.md +10 -12
  5. data/Rakefile +4 -7
  6. data/bin/rail +1 -1
  7. data/lib/rail.rb +7 -21
  8. data/lib/rail/application.rb +10 -82
  9. data/lib/rail/browser.rb +6 -10
  10. data/lib/rail/generator.rb +13 -20
  11. data/lib/rail/pipeline.rb +13 -13
  12. data/lib/rail/precompiler.rb +58 -0
  13. data/lib/rail/processor/base.rb +1 -1
  14. data/lib/rail/processor/coffee_script.rb +1 -1
  15. data/lib/rail/processor/haml.rb +2 -2
  16. data/lib/rail/request.rb +12 -2
  17. data/lib/rail/tasks/assets.rake +1 -1
  18. data/lib/rail/version.rb +1 -1
  19. data/lib/support/generator.rb +76 -0
  20. data/lib/support/inflector.rb +16 -0
  21. data/lib/support/loader.rb +55 -0
  22. data/lib/support/query_string.rb +8 -0
  23. data/lib/support/query_struct.rb +10 -0
  24. data/rail.gemspec +5 -0
  25. data/spec/{coffee_spec.rb → features/coffee_spec.rb} +5 -7
  26. data/spec/{haml_spec.rb → features/haml_spec.rb} +6 -8
  27. data/spec/{sass_spec.rb → features/sass_spec.rb} +5 -7
  28. data/spec/{project → fixtures/project}/app/assets/javascripts/application.js.coffee +0 -0
  29. data/spec/{project → fixtures/project}/app/assets/javascripts/font.coffee +0 -0
  30. data/spec/{project → fixtures/project}/app/assets/javascripts/parser.js.coffee +0 -0
  31. data/spec/{project → fixtures/project}/app/assets/stylesheets/_reset.scss +0 -0
  32. data/spec/{project → fixtures/project}/app/assets/stylesheets/application.css.scss +0 -0
  33. data/spec/{project → fixtures/project}/app/helpers/application_helper.rb +0 -0
  34. data/spec/{project → fixtures/project}/app/views/articles/about.html.haml +0 -0
  35. data/spec/{project → fixtures/project}/app/views/layouts/application.html.haml +0 -0
  36. data/spec/{project → fixtures/project}/app/views/layouts/articles.html.haml +0 -0
  37. data/spec/{project → fixtures/project}/config/application.rb +0 -0
  38. data/spec/{project → fixtures/project}/controller.rb +0 -0
  39. data/spec/lib/rail/application_spec.rb +38 -0
  40. data/spec/lib/rail/generator_spec.rb +14 -0
  41. data/spec/lib/rail/precompiler_spec.rb +25 -0
  42. data/spec/lib/rail/request_spec.rb +16 -0
  43. data/spec/lib/support/inflector_spec.rb +18 -0
  44. data/spec/lib/support/loader_spec.rb +61 -0
  45. data/spec/lib/support/query_string_spec.rb +11 -0
  46. data/spec/lib/support/query_struct_spec.rb +28 -0
  47. data/spec/spec_helper.rb +6 -0
  48. data/spec/support/common_helper.rb +5 -0
  49. metadata +99 -32
  50. data/lib/generator.rb +0 -73
  51. data/lib/rail/support.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a66f7d5b9a7e1436ce075bcf244d8c020b14b29
4
- data.tar.gz: 0bff180762f3b1be3d8193e8a36cb810ebc39980
3
+ metadata.gz: ed960041649216cdcaeb74ef9689f4e95036b95b
4
+ data.tar.gz: 9f8d32c3ff9f03a87521958d217a0d12c9cde586
5
5
  SHA512:
6
- metadata.gz: 8779ed872c394c8df542f8d15277b235e7c1de0936ead82e8b1c6e6fb129b312d6789ae7f5dd8f3a0d83d7d41de8b2f20d21c12a4d939fee8033559ebcb3dc4a
7
- data.tar.gz: facff4a130a3574032a7b1e5fdd52c5210dff76929260dcd6ad7df54a12f0208d463fbce56cce13525e09960e664c5e9e03ea5a6bfba2b3877f1f9512f9cce51
6
+ metadata.gz: 1738d5b0b7a8725f7e9187edd6f6cc8c96815197167e9e2bf0d50245a27c8d2420807c01d211d0355bc14c98e67ddfccaf43d0dff2ccd93c20f8737cca10c759
7
+ data.tar.gz: 04cc3ad49ca4dbd80fd4144de9d6684b48a007c303bd1fc0e01ef3657fddb9d158871919d738ecacbf40b02129613bcdaae3c66f93ebd419252809eb951461cd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## Rail 0.0.8 (July 29, 2014)
2
+
3
+ * Automatically reload helper modules when they change.
4
+
1
5
  ## Rail 0.0.7 (July 15, 2014)
2
6
 
3
7
  * Added a CLI for generating project directories.
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ watch(%r{^lib/(.+)\.rb$}) do |match|
3
+ file = "spec/lib/#{match[1]}_spec.rb"
4
+ File.exist?(file) ? file : 'spec'
5
+ end
6
+ watch(%r{^spec/.*_spec\.rb$})
7
+ watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
8
+ end
9
+
10
+ # vim: set ft=ruby
data/README.md CHANGED
@@ -8,7 +8,9 @@ assets, and it includes the following components:
8
8
  * [Haml](http://haml.info/) for HTML, and
9
9
  * [Sass](http://sass-lang.com/) for CSS.
10
10
 
11
- ## Straightforward Installation
11
+ ## Installation
12
+
13
+ ### Straightforward
12
14
 
13
15
  Install the gem:
14
16
 
@@ -42,18 +44,14 @@ current directory called `my_project` and initializes a basic Rail project
42
44
  inside that folder. In this case, `MyProject` is used as the class name of
43
45
  the project. Feel free to replace `my_project` with the name of your project.
44
46
 
45
- ## Manual Installation
47
+ ### Manual
46
48
 
47
- Include the gem in your `Gemfile`:
49
+ Create a `Gemfile`:
48
50
 
49
51
  ```ruby
50
52
  source 'https://rubygems.org'
51
53
 
52
- gem 'rail', '~> 0.0.7'
53
-
54
- # The rest is optional
55
- gem 'redcarpet', '~> 3.1.2' # your favorit complement to Haml
56
- gem 'thin', '~> 1.6.2' # your favorit Web server
54
+ gem 'rail'
57
55
  ```
58
56
 
59
57
  Run [Bundler](http://bundler.io/):
@@ -122,15 +120,15 @@ As with Rails, Rail is configured inside `config/application.rb`:
122
120
  ```ruby
123
121
  module MyProject
124
122
  class Application < Rail::Application
125
- # Import assets from other gems:
126
- config.gems << 'turbolinks'
123
+ # Gems to look for additional assets
124
+ config.gems << 'googleplus-reader'
127
125
 
128
- # Precompile assets using `rake assets`:
126
+ # Assets to precompile when running `rake assets`
129
127
  config.precompile << 'application.css'
130
128
  config.precompile << 'application.js'
131
129
  config.precompile << 'index.html'
132
130
 
133
- # Compress assets:
131
+ # Compress assets when serving and precompiling
134
132
  config.compress = true
135
133
  end
136
134
  end
data/Rakefile CHANGED
@@ -1,10 +1,7 @@
1
1
  require 'bundler/gem_tasks'
2
- require 'rake/testtask'
2
+ require 'rspec/core/rake_task'
3
3
 
4
- Rake::TestTask.new do |test|
5
- test.libs.push('lib')
6
- test.test_files = FileList[ 'spec/*_spec.rb' ]
7
- test.verbose = true
8
- end
4
+ RSpec::Core::RakeTask.new(:spec)
9
5
 
10
- task :default => :test
6
+ task :default => :spec
7
+ task :test => :spec
data/bin/rail CHANGED
@@ -10,7 +10,7 @@ unless ARGV.length == 2 && ARGV[0] == 'new'
10
10
  end
11
11
 
12
12
  begin
13
- Rail::Generator.new(root_dir: ARGV[1]).run
13
+ Rail::Generator.new(destination: ARGV[1]).run
14
14
  rescue Rail::Generator::Error => e
15
15
  puts e
16
16
  exit 1
data/lib/rail.rb CHANGED
@@ -1,29 +1,30 @@
1
- require 'ostruct'
2
1
  require 'forwardable'
3
-
4
2
  require 'rack'
5
-
6
3
  require 'coffee-script'
7
4
  require 'haml'
8
5
  require 'sass'
9
-
10
6
  require 'uglifier'
11
7
 
8
+ require_relative 'support/inflector'
9
+ require_relative 'support/loader'
10
+ require_relative 'support/query_string'
11
+ require_relative 'support/query_struct'
12
+
12
13
  require_relative 'rail/application'
13
14
  require_relative 'rail/browser'
14
15
  require_relative 'rail/context'
15
16
  require_relative 'rail/pipeline'
17
+ require_relative 'rail/precompiler'
16
18
  require_relative 'rail/processor'
17
19
  require_relative 'rail/request'
18
20
  require_relative 'rail/server'
19
- require_relative 'rail/support'
20
21
  require_relative 'rail/version'
21
22
 
22
23
  module Rail
23
24
  NotFoundError = Class.new(StandardError)
24
25
 
25
26
  def self.env
26
- @env ||= build_env
27
+ @env ||= Support::QueryString.new(ENV['RAIL_ENV'] || 'development')
27
28
  end
28
29
 
29
30
  def self.applications
@@ -31,19 +32,4 @@ module Rail
31
32
  klass < Application
32
33
  end
33
34
  end
34
-
35
- private
36
-
37
- def self.build_env
38
- string = ENV['RAIL_ENV'] ? ENV['RAIL_ENV'].dup : 'development'
39
-
40
- string.singleton_class.class_eval do
41
- define_method(:method_missing) do |name, *arguments, &block|
42
- super unless name.to_s =~ /^(?<name>.+)\?$/
43
- self == Regexp.last_match(:name)
44
- end
45
- end
46
-
47
- string
48
- end
49
35
  end
@@ -1,16 +1,11 @@
1
1
  module Rail
2
2
  class Application
3
- extend Forwardable
4
-
5
- attr_reader :browser, :pipeline
6
- def_delegators :config, :root, :gems, :compress?
3
+ attr_reader :config, :browser, :pipeline
7
4
 
8
5
  def initialize
9
- # config.ru
10
- config.root ||= self.class.find_root
11
-
12
- @browser = Browser.new(self)
13
- @pipeline = Pipeline.new(self)
6
+ @config = self.class.config
7
+ @browser = Browser.new(config)
8
+ @pipeline = Pipeline.new(config)
14
9
  end
15
10
 
16
11
  def call(env)
@@ -18,95 +13,28 @@ module Rail
18
13
  (browser.accept?(request) ? browser : pipeline).process(request)
19
14
  end
20
15
 
21
- def helpers
22
- @helpers ||= load_helpers
16
+ def precompile
17
+ Precompiler.new(pipeline).process(config.precompile)
23
18
  end
24
19
 
25
- def config
26
- self.class.config
20
+ def self.inherited(klass)
21
+ klass.config.root = File.expand_path('../..', caller[0].sub(/:.*/, ''))
27
22
  end
28
23
 
29
24
  def self.config
30
- @config ||= build_config
25
+ @config ||= Support::QueryStruct.new(default_options)
31
26
  end
32
27
 
33
28
  def self.load_tasks
34
- # Rakefile
35
- config.root ||= find_root
36
-
37
29
  Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each do |path|
38
30
  Rake::load_rakefile(path)
39
31
  end
40
32
  end
41
33
 
42
- def self.precompile
43
- if config.precompile.empty?
44
- puts 'Nothing to precompile.'
45
- return
46
- end
47
-
48
- application = self.new
49
-
50
- puts 'Precompiling assets...'
51
- puts
52
-
53
- config.precompile.each do |path|
54
- file = File.join('public', path)
55
- unless File.exist?(File.dirname(file))
56
- FileUtils.mkdir_p(File.dirname(file))
57
- end
58
-
59
- puts "#{ path } -> #{ file }"
60
-
61
- request = Request.new('REQUEST_METHOD' => 'GET', 'PATH_INFO' => path)
62
- _, _, source = application.pipeline.process(request)
63
-
64
- File.open(file, 'w') do |file|
65
- source.each { |chunk| file.write(chunk) }
66
- end
67
- end
68
-
69
- puts
70
- puts 'Done.'
71
- end
72
-
73
- def self.find_root
74
- File.expand_path('..', caller[1].sub(/:.*/, ''))
75
- end
76
-
77
34
  private
78
35
 
79
- def load_helpers
80
- Dir[File.join(root, 'app/helpers/*.rb')].map do |file|
81
- require file
82
- Support.constantize(File.basename(file, '.rb'))
83
- end
84
- end
85
-
86
36
  def self.default_options
87
- {
88
- gems: [],
89
- precompile: [],
90
- compress: Rail.env.production?
91
- }
37
+ { gems: [], precompile: [], compress: Rail.env.production? }
92
38
  end
93
-
94
- def self.build_config
95
- struct = OpenStruct.new
96
-
97
- struct.singleton_class.class_eval do
98
- define_method(:method_missing) do |name, *arguments, &block|
99
- !!super(name.to_s.sub(/\?$/, '').to_sym, *arguments, &block)
100
- end
101
- end
102
-
103
- default_options.each do |name, value|
104
- struct.send("#{ name }=", value)
105
- end
106
-
107
- struct
108
- end
109
-
110
- private_class_method :default_options, :build_config
111
39
  end
112
40
  end
data/lib/rail/browser.rb CHANGED
@@ -2,23 +2,19 @@ require 'rack'
2
2
 
3
3
  module Rail
4
4
  class Browser
5
- extend Forwardable
5
+ attr_reader :root
6
6
 
7
- def_delegator :@host, :root
8
- def_delegator :@directory, :call
9
-
10
- def initialize(host)
11
- @host = host
12
- @directory ||= Rack::Directory.new(File.join(root, 'public'))
7
+ def initialize(config)
8
+ @root = File.join(config.root, 'public')
9
+ @directory = Rack::Directory.new(root)
13
10
  end
14
11
 
15
12
  def process(request)
16
- call(request.env)
13
+ @directory.call(request.env)
17
14
  end
18
15
 
19
16
  def accept?(request)
20
- path = request.path
21
- !path.empty? && File.exist?(File.join(root, 'public', path))
17
+ File.exist?(File.join(root, request.path))
22
18
  end
23
19
  end
24
20
  end
@@ -1,9 +1,8 @@
1
- require 'generator'
1
+ require 'support/generator'
2
+ require 'support/inflector'
2
3
 
3
4
  module Rail
4
- class Generator < ::Generator
5
- Error = Class.new(StandardError)
6
-
5
+ class Generator < Support::Generator
7
6
  FILES = [
8
7
  'app/assets/javascripts/application.js.coffee',
9
8
  'app/assets/stylesheets/application.css.scss',
@@ -17,31 +16,25 @@ module Rail
17
16
  ]
18
17
 
19
18
  def initialize(options)
20
- root_dir = options.fetch(:root_dir)
21
- template_dir = File.expand_path('../templates', __FILE__)
22
-
23
- project_name = (root_dir.split('/').last || '')
24
- .gsub(/^[^a-zA-Z]*/, '')
25
- .gsub(/[^\w]/, '')
26
- .gsub(/^\w|_\w/, &:upcase)
27
- .gsub(/_+/, ' ')
19
+ destination = options.fetch(:destination)
20
+ source = File.expand_path('../templates', __FILE__)
28
21
 
22
+ directory = destination.split('/').last || ''
23
+ project_name = Support::Inflector.titelize(directory)
29
24
  class_name = project_name.gsub(' ', '')
30
25
 
31
26
  @locals = { class_name: class_name, project_name: project_name }
32
27
 
33
- raise Error, 'The project name is invalid.' if class_name.empty?
28
+ raise ArgumentError, 'The project name is invalid.' if class_name.empty?
34
29
 
35
- super(root_dir: root_dir, template_dir: template_dir)
30
+ super(destination: destination, source: source)
36
31
  end
37
32
 
38
33
  def run
39
- raise Error, 'The directory already exists.' if File.directory?(root_dir)
40
- super(FILES, @locals)
41
- end
42
-
43
- def report(message)
44
- puts "Creating '#{ message }'..."
34
+ if File.directory?(destination)
35
+ raise ArgumentError, 'The directory already exists.'
36
+ end
37
+ process(FILES, @locals)
45
38
  end
46
39
  end
47
40
  end
data/lib/rail/pipeline.rb CHANGED
@@ -2,14 +2,16 @@ module Rail
2
2
  class Pipeline
3
3
  extend Forwardable
4
4
 
5
- def_delegators :@host, :root, :gems, :helpers, :compress?
5
+ attr_reader :config
6
+ def_delegators :config, :root, :gems, :compress?
6
7
 
7
- def initialize(host)
8
- @host = host
8
+ def initialize(config)
9
+ @config = config
10
+ @loader = Support::Loader.new(File.join(root, 'app/helpers/*.rb'))
9
11
  end
10
12
 
11
13
  def process(request)
12
- context = Context.new(locals: { request: request }, mixins: helpers)
14
+ context = Context.new(locals: { request: request }, mixins: loader.find)
13
15
 
14
16
  asset = rewrite(request.path)
15
17
  klass = Processor.find(asset) or raise NotFoundError
@@ -21,9 +23,9 @@ module Rail
21
23
 
22
24
  headers = { 'Content-Type' => klass.mime_type }
23
25
 
24
- [ 200, headers, Array(body) ]
26
+ [200, headers, Array(body)]
25
27
  rescue NotFoundError
26
- [ 404, {}, [] ]
28
+ [404, {}, []]
27
29
  end
28
30
 
29
31
  def find(asset)
@@ -36,14 +38,12 @@ module Rail
36
38
 
37
39
  private
38
40
 
41
+ attr_reader :loader
42
+
39
43
  def rewrite(path)
40
- if [ '', 'index.html' ].include?(path)
41
- 'layouts/application.html'
42
- elsif File.extname(path).empty?
43
- "#{ path }.html"
44
- else
45
- path
46
- end
44
+ path = path.sub(/^\//, '')
45
+ path = 'layouts/application.html' if path == 'index.html'
46
+ path
47
47
  end
48
48
 
49
49
  def paths
@@ -0,0 +1,58 @@
1
+ module Rail
2
+ class Precompiler
3
+ class Storage
4
+ attr_reader :root
5
+
6
+ def initialize(root = 'public')
7
+ @root = root
8
+ end
9
+
10
+ def write(file, stream)
11
+ file = File.join(root, file)
12
+
13
+ unless File.exist?(File.dirname(file))
14
+ FileUtils.mkdir_p(File.dirname(file))
15
+ end
16
+
17
+ File.open(file, 'w') do |file|
18
+ stream.each { |chunk| file.write(chunk) }
19
+ end
20
+ end
21
+ end
22
+
23
+ def initialize(pipeline, storage = nil)
24
+ @pipeline = pipeline
25
+ @storage = storage || Storage.new
26
+ end
27
+
28
+ def process(paths)
29
+ if paths.empty?
30
+ report('Nothing to precompile.')
31
+ return
32
+ end
33
+
34
+ report('Precompiling assets...')
35
+
36
+ paths.each_with_index do |path, i|
37
+ report('%4d. %s' % [i + 1, path])
38
+ storage.write(path, read(path))
39
+ end
40
+
41
+ report('Done.')
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :pipeline, :storage
47
+
48
+ def read(path)
49
+ request = Request.new('REQUEST_METHOD' => 'GET', 'PATH_INFO' => path)
50
+ _, _, source = pipeline.process(request)
51
+ source
52
+ end
53
+
54
+ def report(message)
55
+ puts message
56
+ end
57
+ end
58
+ end