gurk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
19
+ .ruby-version
20
+ spec/support/testapp
21
+ **.DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gurk.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jason Torres
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # Gurk
2
+
3
+ A ruby microframework for the masses. You don't need a programming background all you need is the english language.
4
+
5
+ Perfect for designers or any developers that don't want to write code at all.
6
+
7
+ ## Installation
8
+
9
+ gem install gurk
10
+
11
+ Create a new gurk project by running
12
+
13
+ gurk new <appname>
14
+ cd <appname>
15
+
16
+ You should see a directory with the following structure
17
+
18
+ app/
19
+ assets/
20
+ views/
21
+ views/layouts/application.html.erb
22
+ features/
23
+ public/
24
+ vendor/
25
+ Gemfile
26
+
27
+ ## Features
28
+
29
+ Create a basic feature file with the following
30
+
31
+ Given I have a home page
32
+ And with the path "/"
33
+ And with the title "Home Page"
34
+ And with the layout "
35
+
36
+ More information and examples can be found at the Wiki.
37
+
38
+ ## Template Support
39
+
40
+ Gurk supports Tilt. A template wrapper that gives you the flexibility to choose which
41
+
42
+ If you're using haml, just add the following in your Gemfile
43
+
44
+ gem 'haml'
45
+
46
+ Don't forget to run bundle install
47
+
48
+ ## Overiding generated pages
49
+
50
+ For each page generated from the feature scenarios. We create an object that you can easily override. For this feature.
51
+
52
+
53
+ Given I have a home page
54
+ And with the path "/"
55
+ And with the title "Home Page"
56
+ And with the layout "
57
+
58
+ Add a file called app/home.rb
59
+
60
+ class HomePage
61
+ include Gurk::Methods
62
+
63
+ local :page_title, 'This is the new title'
64
+ local :header, 'The most awesome site ever'
65
+
66
+ path '/homepage'
67
+
68
+ end
69
+
70
+ ## Creating your own pages
71
+
72
+ Ok fine, you don't want to use the features feature. You are free to do so by doing the following
73
+
74
+ Create a file called app/contact.rb
75
+
76
+ class ContactPage
77
+ include Gurk::Methods
78
+
79
+ name 'contact'
80
+ local :title, "Contact Page"
81
+ path '/contact'
82
+
83
+ end
84
+
85
+ Don't forget to create your view. For example: app/views/contact.html.erb
86
+
87
+ Then register it to Gurk in your app.rb file.
88
+
89
+ Gurk::Router.register ContactPage
90
+
91
+ ## Tests
92
+
93
+ Gurk supports tests! In fact we do sanity check per each request during development.
94
+
95
+ ## Contributing
96
+
97
+ 1. Fork it
98
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
99
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
100
+ 4. Push to the branch (`git push origin my-new-feature`)
101
+ 5. Create new Pull Request
102
+
103
+
104
+ ## Contributors
105
+
106
+ Vixon
107
+
108
+ ## License
109
+
110
+ MIT License
111
+
112
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/bin/gurk ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ # $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
5
+
6
+ require 'gurk/runner'
7
+ Gurk::Runner.start
data/gurk.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gurk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gurk"
8
+ spec.version = Gurk::VERSION
9
+ spec.authors = ["Vixon"]
10
+ spec.email = ["vixonshow@gmail.com"]
11
+ spec.description = %q{Gurk}
12
+ spec.summary = %q{A plain english ruby microframework that makes sense}
13
+ spec.homepage = "http://github.com/vixon/gurk"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "rack-test"
25
+
26
+ spec.add_dependency "gherkin"
27
+ spec.add_dependency 'http_router', '~> 0.11.0'
28
+ spec.add_dependency 'tilt'
29
+ spec.add_dependency 'thor'
30
+ end
data/lib/gurk.rb ADDED
@@ -0,0 +1,65 @@
1
+ require "gurk/version"
2
+ require "gurk/router"
3
+ require "gurk/parser"
4
+ require "gurk/page"
5
+ require "tilt"
6
+ require "tilt/erb"
7
+
8
+ module Gurk
9
+
10
+ Tilt.register Tilt::ERBTemplate, '.html.erb'
11
+
12
+ def self.root
13
+ Dir.pwd
14
+ end
15
+
16
+ # The default template
17
+ @@default_view_engine = :erb
18
+
19
+ def self.default_view_engine
20
+ @@default_view_engine
21
+ end
22
+
23
+ def self.default_view_engine=(new_default_view_engine)
24
+ @@default_view_engine = new_default_view_engine
25
+ end
26
+
27
+ # The default view path
28
+ @@view_path = self.root + "/app/views"
29
+
30
+ def self.view_path
31
+ @@view_path
32
+ end
33
+
34
+ def self.view_path=(new_view_path)
35
+ @@view_path = new_view_path
36
+ end
37
+
38
+ @@feature_paths = Dir.glob("#{Dir.pwd}/features/*.feature")
39
+
40
+ def self.feature_paths
41
+ @@feature_paths
42
+ end
43
+
44
+ def self.feature_paths=(new_feature_path)
45
+ @@feature_paths = new_feature_path
46
+ end
47
+
48
+ @@router ||= Gurk::Router.new
49
+
50
+ def self.router
51
+ @@router
52
+ end
53
+
54
+ def self.run
55
+ puts self.feature_paths
56
+ parsed = Gurk::Parser.new(self.feature_paths).parse!
57
+
58
+ parsed.each do |p|
59
+ router.add Gurk::Page.new(p)
60
+ end
61
+
62
+ self.router
63
+ end
64
+
65
+ end
data/lib/gurk/cli.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'thor'
2
+ module Gurk
3
+ class Cli < Thor::Group
4
+ include Thor::Actions
5
+
6
+ argument :name
7
+
8
+ def self.source_root
9
+ File.dirname(__FILE__)
10
+ end
11
+
12
+ def setup
13
+ directory "../templates", name, recursive: true
14
+ end
15
+
16
+ def bundle_install
17
+ system("cd #{name} && bundle install")
18
+ end
19
+
20
+ end
21
+ end
data/lib/gurk/page.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'erb'
2
+ require 'tilt'
3
+
4
+ module Gurk
5
+ class Page
6
+ attr_accessor :name, :route, :locals, :layout
7
+
8
+ def initialize(data)
9
+ @name = data[:name].downcase
10
+ @locals = data[:locals]
11
+ @route = data[:route]
12
+ @layout= data[:locals][:layout] if data[:locals] && data[:locals][:layout]
13
+ end
14
+
15
+ def render(env)
16
+ output = nil
17
+
18
+ if @layout
19
+ output = render_template_with_layout(env) do
20
+ render_template(env)
21
+ end
22
+ else
23
+ output = render_template(env)
24
+ end
25
+
26
+ [200, {'content_type' => 'text/html'}, [output]]
27
+
28
+ rescue Errno::ENOENT => e
29
+ raise Gurk::TemplateNotFound.new(e)
30
+ rescue RuntimeError, Exception => e
31
+ # TODO: Make this more sensible
32
+ raise e
33
+ end
34
+
35
+ def render_template_with_layout(env, &block)
36
+ tilt = Tilt.new(layout_path)
37
+ tilt.render(nil, locals) do
38
+ yield
39
+ end
40
+ end
41
+
42
+ def render_template(env)
43
+ tilt = Tilt.new(view_path)
44
+ tilt.render(nil, locals)
45
+ end
46
+
47
+ def view_name
48
+ @view_name ||= @name
49
+ end
50
+
51
+ def view_path
52
+ Gurk.view_path + '/' + view_name + '.' + Gurk.default_view_engine.to_s
53
+ end
54
+
55
+ def layout_name
56
+ @locals[:layout]
57
+ end
58
+
59
+ def layout_path
60
+ if layout_name =~ /\.(erb|haml|)/
61
+ Gurk.view_path + '/' + layout_name
62
+ else
63
+ Gurk.view_path + '/' + layout_name + '.' + Gurk.default_view_engine.to_s
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+
70
+ class Gurk::TemplateNotFound < Exception; end
71
+ class Gurk::TemplateEngineNotFound < Exception; end
@@ -0,0 +1,82 @@
1
+ require 'gherkin/parser/parser'
2
+ require 'gherkin/formatter/json_formatter'
3
+ require 'stringio'
4
+ require 'multi_json'
5
+
6
+ module Gurk
7
+ class Parser
8
+ VALID_STEPS = [
9
+ { "^I have a page called '(.+)'$" => lambda { |k, _| { name: k } } },
10
+ { "^it has a route of '(.+)'$" => lambda { |k, _| { route: k } } },
11
+ { "^it has a (.+) called '(.+)'$" => lambda { |k, v| { k.to_sym => v } } }
12
+ ]
13
+
14
+ attr_accessor :sources
15
+
16
+ def initialize(sources = Dir.glob("#{Dir.pwd}/features/*.feature"))
17
+ @parsed_names = []
18
+ @parsed_data = []
19
+ @sources = sources
20
+ io = StringIO.new
21
+ formatter = Gherkin::Formatter::JSONFormatter.new(io)
22
+ parser = Gherkin::Parser::Parser.new(formatter)
23
+ read_feature_files(io, parser, formatter, sources)
24
+ end
25
+
26
+ def parse!
27
+ @parsed_names.each { |name| parse_names(name) }
28
+ parse_locals(@parsed_data)
29
+ end
30
+
31
+ private
32
+
33
+ def read_feature_files(io, parser, formatter, sources)
34
+ sources.each { |s| parser.parse(IO.read(s), s, 0) }
35
+ formatter.done
36
+ process_data(MultiJson.load(io.string))
37
+ end
38
+
39
+ def process_data(data)
40
+ data.each { |feature| extract_steps_from feature['elements'] }
41
+ end
42
+
43
+ def extract_steps_from(element_nodes)
44
+ element_nodes.each { |element_node| @parsed_names << extract_names_from(element_node['steps']) }
45
+ end
46
+
47
+ def extract_names_from(steps)
48
+ [].tap { |name| steps.each { |step| name << step['name'] } }
49
+ end
50
+
51
+ def parse_names(name)
52
+ @parsed_data << name.map { |match| parse_steps(match) }.flatten.compact
53
+ end
54
+
55
+ def parse_steps(match)
56
+ VALID_STEPS.map { |step| step.values.first.call($1, $2) if /#{step.keys.first}/ =~ match }
57
+ end
58
+
59
+ def parse_locals(steps)
60
+ @parsed_data = [].tap do |data|
61
+ steps.map do |step|
62
+ locals = sanitize(step)
63
+ step << { locals: extract_locals_from(step, locals) }
64
+ data << merge_steps(step)
65
+ end
66
+ end
67
+ end
68
+
69
+ def sanitize(step)
70
+ step.dup.reject! { |h| h.key?(:route) || h.key?(:name) }
71
+ end
72
+
73
+ def extract_locals_from(step, locals)
74
+ step.reject! { |h| h == locals.first }
75
+ locals.first
76
+ end
77
+
78
+ def merge_steps(step)
79
+ {}.tap { |data| step.each { |h| data.merge! h } }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+ require 'http_router'
2
+
3
+ module Gurk
4
+ class Router
5
+
6
+ def initialize
7
+ http_router
8
+ end
9
+
10
+ def http_router
11
+ @http_router ||= HttpRouter.new
12
+ end
13
+
14
+ def add(page)
15
+ routes.push(page)
16
+ http_router.add(page.route).to { |env|
17
+ page.render env
18
+ }
19
+ end
20
+
21
+ def routes
22
+ @routes ||= []
23
+ end
24
+
25
+ def call(env)
26
+ http_router.call(env)
27
+ end
28
+
29
+ end
30
+ end
31
+
@@ -0,0 +1,25 @@
1
+ require 'thor'
2
+ require 'gurk/cli'
3
+
4
+ module Gurk
5
+
6
+ class Runner < Thor
7
+
8
+ map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
9
+
10
+ desc "new app_name", "Generates a new Gurk application"
11
+ method_options :as => :string, :relative => :boolean, :force => :boolean
12
+ def new(name)
13
+ Gurk::Cli.new([name]).setup
14
+ say "New Gurk app generated. Now start Gurkin!"
15
+ end
16
+
17
+ desc "version", "Show Gurk version"
18
+ def version
19
+ require 'thor/version'
20
+ say "Gurk #{Gurk::VERSION}"
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,3 @@
1
+ module Gurk
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'gurk'
4
+
5
+ # Uncomment if you want to use haml
6
+ # gem 'haml'
7
+
8
+ # Uncomment if you want to use cucumber
9
+
10
+ # group :test do
11
+ # gem 'cucumber'
12
+ # gem 'rack-test'
13
+ # end
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+ Bundler.require
4
+
5
+ require 'gurk'
6
+ App = Gurk.run
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ require './app'
2
+
3
+ run App = Gurk.run
@@ -0,0 +1,15 @@
1
+ Feature: My site
2
+
3
+ Scenario: Home Page
4
+ Given I have a page called 'Home'
5
+ And it has a title called 'home'
6
+ And it has a route of '/'
7
+ When I visit '/'
8
+ Then I should see 'home'
9
+
10
+ Scenario: About
11
+ Given I have a page called 'About'
12
+ And it has a title called 'About Us'
13
+ And it has a route of '/about'
14
+ When I visit '/about'
15
+ Then I should see 'About Us'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'gurk', path: '../../'
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+ Bundler.require
4
+
5
+ require 'gurk'
6
+ App = Gurk.run
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <title><%= title %></title>
3
+
4
+ <body>
5
+ <p>Hey You,</p>
6
+ <p>Keep being awesome. Because being awesome is awesome.</p>
7
+ <p>- You</p>
8
+
9
+ </body>
10
+
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <title><%= title %></title>
3
+
4
+ <body>
5
+ <p>Hey You,</p>
6
+ <p>Keep being awesome. Because being awesome is awesome.</p>
7
+ <p>- You</p>
8
+
9
+ </body>
10
+
11
+ </html>
@@ -0,0 +1,3 @@
1
+ require './app'
2
+
3
+ run App = Gurk.run
@@ -0,0 +1,15 @@
1
+ Feature: My site
2
+
3
+ Scenario: Home Page
4
+ Given I have a page called 'Home'
5
+ And it has a title called 'home'
6
+ And it has a route of '/'
7
+ When I visit '/'
8
+ Then I should see 'home'
9
+
10
+ Scenario: About
11
+ Given I have a page called 'About'
12
+ And it has a title called 'About Us'
13
+ And it has a route of '/about'
14
+ When I visit '/about'
15
+ Then I should see 'About Us'
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gurk::Cli do
4
+
5
+ let(:sample_directory) {
6
+ File.join(Dir.pwd, "spec", "support", "testapp")
7
+ }
8
+
9
+ before do
10
+ FileUtils.rm_rf sample_directory
11
+
12
+ ARGV.replace []
13
+ ARGV << sample_directory
14
+
15
+ cli = Gurk::Cli.new ARGV
16
+ cli.setup
17
+ end
18
+
19
+ describe "#setup" do
20
+
21
+ it 'creates the app directory' do
22
+ expect(File.exists?(sample_directory)).to be_true
23
+ end
24
+
25
+ it 'creates individual app files' do
26
+ expect(File.exists?(File.join(sample_directory, 'config.ru'))).to be_true
27
+ expect(File.exists?(File.join(sample_directory, 'app.rb'))).to be_true
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
@@ -0,0 +1,27 @@
1
+ require 'rack/test'
2
+ require File.join(File.dirname(__FILE__), '/../example/app.rb')
3
+
4
+ include Rack::Test::Methods
5
+
6
+ describe 'Gurk::Example' do
7
+
8
+ before do
9
+ Gurk.stub(:view_path).and_return File.join('spec', 'example', 'app', 'views')
10
+ Gurk.stub(:feature_paths).and_return Dir.glob("#{Dir.pwd}/spec/example/features/*.feature")
11
+
12
+ request '/'
13
+ end
14
+
15
+ def app
16
+ Gurk.run
17
+ end
18
+
19
+ it 'returns homepage successfully' do
20
+ expect(last_response.status).to eq(200)
21
+ end
22
+
23
+ it 'shows the title' do
24
+ expect(last_response.body).to include ('home')
25
+ end
26
+
27
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ include Rack::Test::Methods
4
+
5
+ describe Gurk do
6
+
7
+ describe '#run' do
8
+
9
+ before do
10
+ Gurk.stub(:feature_paths).and_return Dir.glob("#{Dir.pwd}/spec/support/*.feature")
11
+ Gurk.run
12
+ end
13
+
14
+ it 'creates routes from the array' do
15
+ expect(Gurk.router.routes.length).to_not be_zero
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gurk::Page do
4
+
5
+ describe '#pages' do
6
+
7
+ Gurk.view_path = File.join(Dir.pwd, 'spec', 'support', 'views')
8
+
9
+ let(:page) {
10
+ Gurk::Page.new({name: 'about', path: '/pages/slug', locals: {title: 'lalala'}})
11
+ }
12
+
13
+ it 'returns the view name' do
14
+ expect(page.view_name).to eq('about')
15
+ end
16
+
17
+ context "nolayout" do
18
+ it 'returns the layout name' do
19
+ expect(page.layout_name).to be_nil
20
+ end
21
+ end
22
+
23
+ context "with a layout" do
24
+ it 'returns the layout name' do
25
+ page.locals.merge!(layout: 'wat')
26
+ expect(page.layout_name).to eq 'wat'
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#render' do
32
+
33
+ it 'render the page' do
34
+ page = Gurk::Page.new({name: 'about', path: '/pages/slug', locals: {title: 'lalala'}})
35
+ result = page.render nil
36
+ expect(result.last.first).to include 'lalala'
37
+ end
38
+
39
+ it 'renders the page with the layout' do
40
+ page = Gurk::Page.new({name: 'about', path: '/pages/slug', locals: {title: 'lalala', layout: 'layout.erb'}})
41
+ result = page.render nil
42
+
43
+ expect(result.last.first).to include 'This is the layout'
44
+ expect(result.last.first).to include 'lalala'
45
+ end
46
+
47
+ it 'raises an exception if the template is invalid' do
48
+ page = Gurk::Page.new({name: 'aboutlalala', path: '/pages/slug', locals: {title: 'lalala'}})
49
+ expect {
50
+ page.render nil
51
+ }.to raise_exception(Gurk::TemplateNotFound)
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gurk::Parser do
4
+
5
+ let(:sources) do
6
+ #Dir.glob("#{Dir.pwd}/spec/support/*.feature")
7
+ [ "#{Dir.pwd}/spec/support/another_example.feature", "#{Dir.pwd}/spec/support/example.feature" ]
8
+ end
9
+
10
+ let(:parsed_data) do
11
+ [
12
+ { :name => "About", :route => "/about", :locals => { :title=>"about" } },
13
+ { :name => "Home", :route => "/", :locals => { :title => "home" } }
14
+ ]
15
+ end
16
+
17
+ let(:steps) do
18
+ [ ["I have a page called 'About'",
19
+ "it has a title called 'about'",
20
+ "it has a route of '/about'",
21
+ "I visit '/about'",
22
+ "I should see 'about'",],
23
+ ["I have a page called 'Home'",
24
+ "it has a title called 'home'",
25
+ "it has a route of '/'",
26
+ "I visit '/'",
27
+ "I should see 'home'"] ]
28
+ end
29
+
30
+ let(:parsed_steps) do
31
+ [ {"keyword"=>"Given ", "name"=>"I have a page called 'About'", "line"=>4},
32
+ {"keyword"=>"And ", "name"=>"it has a title called 'about'", "line"=>5},
33
+ {"keyword"=>"And ", "name"=>"it has a route of '/about'", "line"=>6},
34
+ {"keyword"=>"When ", "name"=>"I visit '/about'", "line"=>7},
35
+ {"keyword"=>"Then ", "name"=>"I should see 'about'", "line"=>8}]
36
+ [ {"keyword"=>"Given ", "name"=>"I have a page called 'Home'", "line"=>4},
37
+ {"keyword"=>"And ", "name"=>"it has a title called 'home'", "line"=>5},
38
+ {"keyword"=>"And ", "name"=>"it has a route of '/'", "line"=>6},
39
+ {"keyword"=>"When ", "name"=>"I visit '/'", "line"=>7},
40
+ {"keyword"=>"Then ", "name"=>"I should see 'home'", "line"=>8}]
41
+ end
42
+
43
+ let(:parsed_names) do
44
+ [ ["I have a page called 'About'",
45
+ "it has a title called 'about'",
46
+ "it has a route of '/about'",
47
+ "I visit '/about'",
48
+ "I should see 'about'"],
49
+ ["I have a page called 'Home'",
50
+ "it has a title called 'home'",
51
+ "it has a route of '/'",
52
+ "I visit '/'",
53
+ "I should see 'home'"] ]
54
+ end
55
+
56
+ describe '#initialize' do
57
+ it 'reads existing feature files' do
58
+ Gurk::Parser.any_instance.should_receive(:read_feature_files)
59
+ Gurk::Parser.new(sources)
60
+ end
61
+ end
62
+
63
+ describe '#parse!' do
64
+ it 'parses each set of names extracted from the feature files' do
65
+ Gurk::Parser
66
+ .any_instance
67
+ .should_receive(:parse_names)
68
+ .exactly(parsed_names.length)
69
+ .times
70
+ Gurk::Parser.new(sources).parse!
71
+ end
72
+
73
+ it 'passes the parsed data to #parse_locals' do
74
+ parser = Gurk::Parser.new(sources)
75
+ Gurk::Parser
76
+ .any_instance
77
+ .should_receive(:parse_locals)
78
+ .with(parser.instance_variable_get :@parsed_data)
79
+ parser.parse!
80
+ end
81
+
82
+ it 'returns a hash with the correct format' do
83
+ expect(Gurk::Parser.new(sources).parse!).to eq parsed_data
84
+ end
85
+ end
86
+
87
+ describe 'private methods' do
88
+ let(:parser) { Gurk::Parser.new(sources) }
89
+
90
+ describe '#read_feature_files' do
91
+ it 'parses the feature files' do
92
+ Gherkin::Parser::Parser
93
+ .any_instance
94
+ .should_receive(:parse)
95
+ .exactly(parsed_names.length)
96
+ .times
97
+ Gurk::Parser.new(sources)
98
+ end
99
+
100
+ it 'passes the result to #process_data' do
101
+ Gurk::Parser.any_instance.should_receive(:process_data)
102
+ Gurk::Parser.new(sources)
103
+ end
104
+ end
105
+
106
+ describe '#process_data' do
107
+ it 'finds all "elements" nodes in the given data and passes it to #extract_steps_from' do
108
+ Gurk::Parser
109
+ .any_instance
110
+ .should_receive(:extract_steps_from)
111
+ .twice # Two 'element' nodes
112
+ Gurk::Parser.new(sources)
113
+ end
114
+ end
115
+
116
+ describe '#extract_steps_from' do
117
+ it 'finds all "steps" nodes in the given data and passes it to #extract_names_from' do
118
+ Gurk::Parser
119
+ .any_instance
120
+ .should_receive(:extract_names_from)
121
+ .twice # Two 'steps' nodes
122
+ Gurk::Parser.new(sources)
123
+ end
124
+
125
+ it 'saves the return value of #extract_names_from' do
126
+ expect(parser.instance_variable_get :@parsed_names).to eq parsed_names
127
+ end
128
+ end
129
+
130
+ describe '#extract_names_from' do
131
+ it 'finds and returns all "name" nodes from the given data' do
132
+ expect(parser.send(:extract_names_from, parsed_steps)).to eq parsed_names.last
133
+ end
134
+ end
135
+
136
+ describe '#parse_names' do
137
+ it 'passes the given data to #parse_steps' do
138
+ Gurk::Parser
139
+ .any_instance
140
+ .should_receive(:parse_names)
141
+ .exactly(parsed_names.length)
142
+ .times
143
+ Gurk::Parser.new(sources).parse!
144
+ end
145
+ end
146
+
147
+ describe '#parse_steps' do
148
+ context 'with a matching step' do
149
+ it 'returns the parsed step' do
150
+ expect(parser.send(:parse_steps, "I have a page called 'About'")).to include name: 'About'
151
+ end
152
+ end
153
+
154
+ context 'with a non-matching step' do
155
+ it 'returns an array of nils' do
156
+ expect(parser.send(:parse_steps, "I visit '/about'")).to eq [nil, nil, nil]
157
+ end
158
+ end
159
+ end
160
+
161
+ describe '#parse_locals' do
162
+ let(:step) { [[{:name=>"About"}, {:title=>"about"}, {:route=>"/about"}]] }
163
+
164
+ it 'passes each given step to #sanitize' do
165
+ parser.stub(:extract_locals_from)
166
+ parser.should_receive(:sanitize)
167
+ parser.send :parse_locals, step
168
+ end
169
+
170
+ it 'passes sanitized steps to #extract_locals_from' do
171
+ parser.should_receive(:extract_locals_from)
172
+ parser.send :parse_locals, step
173
+ end
174
+
175
+ it 'passes extracted locals to #merge_steps' do
176
+ parser.should_receive(:merge_steps)
177
+ parser.send :parse_locals, step
178
+ end
179
+
180
+ it 'returns the result of the parsing' do
181
+ result = [{:name=>"About", :route=>"/about", :locals => {:title=>"about"}}]
182
+ parser.instance_variable_set(:@parsed_data, step)
183
+ expect(parser.send :parse_locals, step).to eq result
184
+ end
185
+ end
186
+
187
+ describe '#sanitize' do
188
+ it 'returns local variable pairs' do
189
+ step = [{:name=>"About"}, {:title=>"about"}, {:route=>"/about"}]
190
+ expect(parser.send :sanitize, step).to eq [{:title=>"about"}]
191
+ end
192
+ end
193
+
194
+ describe '#extract_locals_from' do
195
+ it 'returns parsed locals' do
196
+ step = [[{:name=>"About"}, {:title=>"about"}, {:route=>"/about"}]]
197
+ local = [{:title=>"about"}]
198
+ expect(parser.send :extract_locals_from, step, local).to eq local.first
199
+ end
200
+ end
201
+
202
+ describe '#merge_steps' do
203
+ it 'returns merged steps' do
204
+ step = [{:name=>"About"}, {:route=>"/about"}, {:locals=>[{:title=>"about"}]}]
205
+ result = { :name => "About", :route => "/about", :locals => [ { :title=>"about" } ] }
206
+ expect(parser.send :merge_steps, step).to eq result
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__), '/../', 'spec_helper')
2
+
3
+ include Rack::Test::Methods
4
+
5
+ describe Gurk::Router do
6
+
7
+ before do
8
+ @router = Gurk::Router.new
9
+ end
10
+
11
+ def app
12
+ @router
13
+ end
14
+
15
+ it 'returns a valid instance' do
16
+ expect(@router).to be_instance_of Gurk::Router
17
+ end
18
+
19
+ it 'returns a valid http_router instance' do
20
+ expect(@router.http_router).to be_instance_of HttpRouter
21
+ end
22
+
23
+ it 'adds a page with a valid content' do
24
+ page = Gurk::Page.new({name: 'about', path: '/about', locals: {title: 'lalala'}})
25
+
26
+ @router.add page
27
+
28
+ request "/about"
29
+
30
+ expect(last_response.status).to eq(200)
31
+ end
32
+
33
+ it 'adds a page with a valid content with params' do
34
+
35
+ page = Gurk::Page.new({name: 'about', path: '/pages/slug', locals: {title: 'lalala'}})
36
+
37
+ @router.add page
38
+
39
+ request '/pages/this-is-a-slug'
40
+
41
+ expect(last_response.status).to eq(200)
42
+ end
43
+
44
+ end
@@ -0,0 +1,8 @@
1
+ require 'gurk'
2
+ require 'gurk/router'
3
+ require 'gurk/page'
4
+ require 'gurk/parser'
5
+ require 'gurk/cli'
6
+
7
+ require 'rack/test'
8
+
@@ -0,0 +1,8 @@
1
+ Feature: About Page
2
+
3
+ Scenario:
4
+ Given I have a page called 'About'
5
+ And it has a title called 'about'
6
+ And it has a route of '/about'
7
+ When I visit '/about'
8
+ Then I should see 'about'
@@ -0,0 +1,8 @@
1
+ Feature: Home Page
2
+
3
+ Scenario:
4
+ Given I have a page called 'Home'
5
+ And it has a title called 'home'
6
+ And it has a route of '/'
7
+ When I visit '/'
8
+ Then I should see 'home'
@@ -0,0 +1,10 @@
1
+ Feature: Home Page
2
+
3
+ Scenario:
4
+ Given I have a page called 'Home'
5
+ And it has a title called 'home'
6
+ And it has a layout called 'home'
7
+ And it has a template called 'home.html.erb'
8
+ And it has a route of '/'
9
+ When I visit '/'
10
+ Then I should see 'home'
@@ -0,0 +1 @@
1
+ Title: <%= title %>
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <body>
3
+ <p>This is the layout</p>
4
+ <div><%= yield %></div>
5
+ </body>
6
+ </html>
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gurk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vixon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70173898733100 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70173898733100
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70173898732340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70173898732340
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70173898731580 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70173898731580
47
+ - !ruby/object:Gem::Dependency
48
+ name: rack-test
49
+ requirement: &70173898731080 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70173898731080
58
+ - !ruby/object:Gem::Dependency
59
+ name: gherkin
60
+ requirement: &70173898730580 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70173898730580
69
+ - !ruby/object:Gem::Dependency
70
+ name: http_router
71
+ requirement: &70173898729900 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.11.0
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70173898729900
80
+ - !ruby/object:Gem::Dependency
81
+ name: tilt
82
+ requirement: &70173898729400 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70173898729400
91
+ - !ruby/object:Gem::Dependency
92
+ name: thor
93
+ requirement: &70173898728840 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *70173898728840
102
+ description: Gurk
103
+ email:
104
+ - vixonshow@gmail.com
105
+ executables:
106
+ - gurk
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - .gitignore
111
+ - .rspec
112
+ - Gemfile
113
+ - LICENSE.txt
114
+ - README.md
115
+ - Rakefile
116
+ - bin/gurk
117
+ - gurk.gemspec
118
+ - lib/gurk.rb
119
+ - lib/gurk/cli.rb
120
+ - lib/gurk/page.rb
121
+ - lib/gurk/parser.rb
122
+ - lib/gurk/router.rb
123
+ - lib/gurk/runner.rb
124
+ - lib/gurk/version.rb
125
+ - lib/templates/Gemfile
126
+ - lib/templates/app.rb
127
+ - lib/templates/app/views/home.erb
128
+ - lib/templates/app/views/layout.erb
129
+ - lib/templates/config.ru
130
+ - lib/templates/features/home.feature
131
+ - spec/example/Gemfile
132
+ - spec/example/app.rb
133
+ - spec/example/app/views/about.erb
134
+ - spec/example/app/views/home.erb
135
+ - spec/example/config.ru
136
+ - spec/example/features/home.feature
137
+ - spec/gurk/cli_spec.rb
138
+ - spec/gurk/example_spec.rb
139
+ - spec/gurk/gurk_spec.rb
140
+ - spec/gurk/page_spec.rb
141
+ - spec/gurk/parser_spec.rb
142
+ - spec/gurk/router_spec.rb
143
+ - spec/spec_helper.rb
144
+ - spec/support/another_example.feature
145
+ - spec/support/example.feature
146
+ - spec/support/example_with_layout.feature
147
+ - spec/support/views/about.erb
148
+ - spec/support/views/layout.erb
149
+ homepage: http://github.com/vixon/gurk
150
+ licenses:
151
+ - MIT
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ! '>='
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 1.8.15
171
+ signing_key:
172
+ specification_version: 3
173
+ summary: A plain english ruby microframework that makes sense
174
+ test_files:
175
+ - spec/example/Gemfile
176
+ - spec/example/app.rb
177
+ - spec/example/app/views/about.erb
178
+ - spec/example/app/views/home.erb
179
+ - spec/example/config.ru
180
+ - spec/example/features/home.feature
181
+ - spec/gurk/cli_spec.rb
182
+ - spec/gurk/example_spec.rb
183
+ - spec/gurk/gurk_spec.rb
184
+ - spec/gurk/page_spec.rb
185
+ - spec/gurk/parser_spec.rb
186
+ - spec/gurk/router_spec.rb
187
+ - spec/spec_helper.rb
188
+ - spec/support/another_example.feature
189
+ - spec/support/example.feature
190
+ - spec/support/example_with_layout.feature
191
+ - spec/support/views/about.erb
192
+ - spec/support/views/layout.erb