rail 0.0.7 → 0.0.8

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 (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