rodakase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +29 -0
  5. data/CHANGELOG.md +8 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +24 -0
  8. data/LICENSE +22 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +114 -0
  11. data/Rakefile +4 -0
  12. data/benchmarks/templates/button.erb +1 -0
  13. data/benchmarks/view.rb +27 -0
  14. data/lib/roda/plugins/flow.rb +71 -0
  15. data/lib/rodakase.rb +8 -0
  16. data/lib/rodakase/application.rb +32 -0
  17. data/lib/rodakase/cli.rb +9 -0
  18. data/lib/rodakase/component.rb +40 -0
  19. data/lib/rodakase/config.rb +21 -0
  20. data/lib/rodakase/container.rb +127 -0
  21. data/lib/rodakase/transaction.rb +43 -0
  22. data/lib/rodakase/transaction/matcher.rb +31 -0
  23. data/lib/rodakase/transaction/result.rb +52 -0
  24. data/lib/rodakase/version.rb +3 -0
  25. data/lib/rodakase/view.rb +2 -0
  26. data/lib/rodakase/view/layout.rb +98 -0
  27. data/lib/rodakase/view/part.rb +53 -0
  28. data/lib/rodakase/view/renderer.rb +67 -0
  29. data/rodakase.gemspec +34 -0
  30. data/skeletons/simple/Gemfile +9 -0
  31. data/skeletons/simple/Rakefile +4 -0
  32. data/skeletons/simple/bin/console +6 -0
  33. data/skeletons/simple/config.ru +3 -0
  34. data/skeletons/simple/config/application.yml +4 -0
  35. data/skeletons/simple/core/boot.rb +12 -0
  36. data/skeletons/simple/core/simple/application.rb +16 -0
  37. data/skeletons/simple/core/simple/container.rb +11 -0
  38. data/skeletons/simple/core/simple/import.rb +9 -0
  39. data/skeletons/simple/lib/entities/user.rb +3 -0
  40. data/skeletons/simple/log/.gitkeep +0 -0
  41. data/skeletons/simple/spec/routes/heartbeat_spec.rb +9 -0
  42. data/skeletons/simple/spec/spec_helper.rb +12 -0
  43. data/skeletons/simple/spec/unit/user_spec.rb +17 -0
  44. data/skeletons/simple/spec/web_helper.rb +20 -0
  45. data/skeletons/simple/web/routes/root.rb +3 -0
  46. data/spec/dummy/apps/main/core/boot.rb +9 -0
  47. data/spec/dummy/apps/main/core/main/application.rb +17 -0
  48. data/spec/dummy/apps/main/core/main/container.rb +12 -0
  49. data/spec/dummy/apps/main/core/main/import.rb +9 -0
  50. data/spec/dummy/apps/main/core/main/requests.rb +21 -0
  51. data/spec/dummy/apps/main/core/main/view.rb +19 -0
  52. data/spec/dummy/apps/main/lib/entities/user.rb +3 -0
  53. data/spec/dummy/apps/main/lib/persistence/repositories/users.rb +14 -0
  54. data/spec/dummy/apps/main/lib/transaction.rb +11 -0
  55. data/spec/dummy/apps/main/lib/transactions/register_user.rb +17 -0
  56. data/spec/dummy/apps/main/lib/views/users/index.rb +15 -0
  57. data/spec/dummy/apps/main/requests/users.rb +5 -0
  58. data/spec/dummy/apps/main/web/routes/users.rb +21 -0
  59. data/spec/dummy/apps/main/web/templates/layouts/app.slim +6 -0
  60. data/spec/dummy/apps/main/web/templates/users/index.slim +3 -0
  61. data/spec/dummy/apps/main/web/templates/users/index/_list.slim +3 -0
  62. data/spec/dummy/apps/main/web/templates/users/index/_list_item.slim +1 -0
  63. data/spec/dummy/bin/console +6 -0
  64. data/spec/dummy/config.ru +3 -0
  65. data/spec/dummy/config/application.yml +4 -0
  66. data/spec/dummy/core/boot.rb +15 -0
  67. data/spec/dummy/core/dummy/container.rb +14 -0
  68. data/spec/dummy/core/dummy/import.rb +9 -0
  69. data/spec/dummy/lib/persistence/db.rb +13 -0
  70. data/spec/dummy/log/.gitkeep +0 -0
  71. data/spec/fixtures/templates/hello.slim +1 -0
  72. data/spec/fixtures/templates/layouts/app.slim +6 -0
  73. data/spec/fixtures/templates/shared/_index_table.slim +2 -0
  74. data/spec/fixtures/templates/shared/_shared_hello.slim +1 -0
  75. data/spec/fixtures/templates/tasks.slim +3 -0
  76. data/spec/fixtures/templates/user.slim +2 -0
  77. data/spec/fixtures/templates/users.slim +3 -0
  78. data/spec/fixtures/templates/users/_row.slim +2 -0
  79. data/spec/fixtures/templates/users/_tbody.slim +5 -0
  80. data/spec/fixtures/test/core/boot/bar.rb +5 -0
  81. data/spec/fixtures/test/lib/test/dep.rb +4 -0
  82. data/spec/fixtures/test/lib/test/foo.rb +5 -0
  83. data/spec/fixtures/test/lib/test/models.rb +4 -0
  84. data/spec/fixtures/test/lib/test/models/book.rb +6 -0
  85. data/spec/fixtures/test/lib/test/models/user.rb +6 -0
  86. data/spec/integration/application_spec.rb +21 -0
  87. data/spec/integration/transaction_spec.rb +85 -0
  88. data/spec/integration/view_spec.rb +65 -0
  89. data/spec/request/users_spec.rb +35 -0
  90. data/spec/spec_helper.rb +44 -0
  91. data/spec/support/helpers.rb +15 -0
  92. data/spec/unit/component_spec.rb +60 -0
  93. data/spec/unit/container_spec.rb +51 -0
  94. data/spec/unit/view/layout_spec.rb +49 -0
  95. data/spec/unit/view/part_spec.rb +55 -0
  96. data/spec/unit/view/renderer_spec.rb +29 -0
  97. metadata +359 -0
@@ -0,0 +1,67 @@
1
+ require 'tilt'
2
+ require 'dry-equalizer'
3
+
4
+ module Rodakase
5
+ module View
6
+ class Renderer
7
+ include Dry::Equalizer(:dir, :root, :engine)
8
+
9
+ TemplateNotFoundError = Class.new(StandardError)
10
+
11
+ attr_reader :dir, :root, :engine, :tilts
12
+
13
+ def self.tilts
14
+ @__engines__ ||= {}
15
+ end
16
+
17
+ def initialize(dir, options = {})
18
+ @dir = dir
19
+ @root = options.fetch(:root, dir)
20
+ @engine = options[:engine]
21
+ @tilts = self.class.tilts
22
+ end
23
+
24
+ def call(template, scope, &block)
25
+ path = lookup(template)
26
+
27
+ if path
28
+ render(path, scope, &block)
29
+ else
30
+ raise TemplateNotFoundError, "Template #{template} could not be looked up within #{root}"
31
+ end
32
+ end
33
+
34
+ def render(path, scope, &block)
35
+ tilt(path).render(scope, &block)
36
+ end
37
+
38
+ def tilt(path)
39
+ tilts.fetch(path) { tilts[path] = Tilt[engine].new(path) }
40
+ end
41
+
42
+ def lookup(name)
43
+ template?(name) || template?("shared/#{name}") || !root? && chdir('..').lookup(name)
44
+ end
45
+
46
+ def root?
47
+ dir == root
48
+ end
49
+
50
+ def template?(name)
51
+ template_path = path(name)
52
+
53
+ if File.exist?(template_path)
54
+ template_path
55
+ end
56
+ end
57
+
58
+ def path(name)
59
+ dir.join("#{name}.#{engine}")
60
+ end
61
+
62
+ def chdir(dirname)
63
+ self.class.new(dir.join(dirname), engine: engine, root: root)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rodakase/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rodakase"
8
+ spec.version = Rodakase::VERSION
9
+ spec.authors = ["Piotr Solnica"]
10
+ spec.email = ["piotr.solnica@gmail.com"]
11
+ spec.summary = "Lightweight web application stack on top of Roda"
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/solnic/rodakase"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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_runtime_dependency "inflecto", "~> 0"
22
+ spec.add_runtime_dependency "roda", "~> 2.7"
23
+ spec.add_runtime_dependency "tilt", "~> 2.0"
24
+ spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
25
+ spec.add_runtime_dependency "dry-container", "~> 0.2"
26
+ spec.add_runtime_dependency "dry-configurable", "~> 0.1"
27
+ spec.add_runtime_dependency "dry-auto_inject", "~> 0.1"
28
+ spec.add_runtime_dependency "transflow", "~> 0.3"
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.7"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec", "~> 3.1"
33
+ spec.add_development_dependency "capybara", "~> 2.5"
34
+ end
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rodakase'
4
+ gem 'pry'
5
+
6
+ group :test do
7
+ gem 'rack-test'
8
+ gem 'rspec'
9
+ end
@@ -0,0 +1,4 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+ task default: [:spec]
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rodakase/cli'
4
+ require_relative '../core/boot'
5
+
6
+ Rodakase::Cli.start
@@ -0,0 +1,3 @@
1
+ require_relative 'core/boot'
2
+
3
+ run Simple::Application.freeze.app
@@ -0,0 +1,4 @@
1
+ development:
2
+ SOMETHING: 'goes-here'
3
+ test:
4
+ SOMETHING: 'goes-here'
@@ -0,0 +1,12 @@
1
+ require_relative 'simple/container'
2
+
3
+ Simple::Container.finalize! do |container|
4
+ # Register your additional dependencies used by the web app
5
+ #
6
+ # In example a logger:
7
+ #
8
+ # require 'logger'
9
+ # container.register(:logger, Logger.new(container.root.join("log/#{container.config.env}.log")))
10
+ end
11
+
12
+ require 'simple/application'
@@ -0,0 +1,16 @@
1
+ require 'rodakase/application'
2
+
3
+ module Simple
4
+ class Application < Rodakase::Application
5
+ configure do |config|
6
+ config.routes = 'web/routes'.freeze
7
+ config.container = Container
8
+ end
9
+
10
+ route do |r|
11
+ r.multi_route
12
+ end
13
+
14
+ load_routes!
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ require 'rodakase/container'
2
+
3
+ module Simple
4
+ class Container < Rodakase::Container
5
+ setting :auto_register, 'lib'
6
+
7
+ configure do
8
+ load_paths!('lib')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'container'
2
+
3
+ module Simple
4
+ Import = Container.import_module
5
+
6
+ def self.Import(*args)
7
+ Import[*args]
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Entities
2
+ User = Struct.new(:id, :name)
3
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ require 'web_helper'
2
+
3
+ RSpec.describe '/hearbeat', type: :request do
4
+ it 'works' do
5
+ get '/heartbeat'
6
+
7
+ expect(last_response).to be_ok
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ # set the env here since the app config loaded by container uses this name by
2
+ # default
3
+ ENV['RACK_ENV'] = 'test'
4
+
5
+ # Only load the container, if a test needs the whole web stack it should require
6
+ # web_helper instead
7
+ require_relative '../core/simple/container'
8
+
9
+ RSpec.configure do |config|
10
+ # Obviously
11
+ config.disable_monkey_patching!
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'entities/user'
2
+
3
+ RSpec.describe Entities::User do
4
+ subject(:user) { Entities::User.new(1, 'Jane') }
5
+
6
+ describe '#id' do
7
+ it 'works' do
8
+ expect(user.id).to be(1)
9
+ end
10
+ end
11
+
12
+ describe '#name' do
13
+ it 'works too' do
14
+ expect(user.name).to eql('Jane')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rack/test'
4
+
5
+ require_relative '../core/boot'
6
+
7
+ module AppHelper
8
+ def app
9
+ Simple::Application.app
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.before(:suite) do
15
+ Simple::Application.freeze
16
+ end
17
+
18
+ config.include Rack::Test::Methods, type: :request
19
+ config.include AppHelper, type: :request
20
+ end
@@ -0,0 +1,3 @@
1
+ class Simple::Application < Rodakase::Application
2
+ plugin :heartbeat
3
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'main/container'
2
+
3
+ Main::Container.finalize!
4
+
5
+ require 'main/application'
6
+ require 'main/view'
7
+ require 'main/requests'
8
+
9
+ Main::Container.require('requests/**/*.rb')
@@ -0,0 +1,17 @@
1
+ require 'rodakase/application'
2
+ require_relative 'container'
3
+
4
+ module Main
5
+ class Application < Rodakase::Application
6
+ configure do |config|
7
+ config.routes = 'web/routes'.freeze
8
+ config.container = Main::Container
9
+ end
10
+
11
+ route do |r|
12
+ r.multi_route
13
+ end
14
+
15
+ load_routes!
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ require 'rodakase/container'
2
+
3
+ module Main
4
+ class Container < Rodakase::Container
5
+ setting :root, Pathname(__FILE__).join('../..').realpath.dirname.freeze
6
+ setting :auto_register, 'lib'
7
+
8
+ configure do
9
+ load_paths!('lib')
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'container'
2
+
3
+ module Main
4
+ Import = Main::Container.import_module
5
+
6
+ def self.Import(*args)
7
+ Import[*args]
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'container'
2
+
3
+ module Main
4
+ module Requests
5
+ class Registrar
6
+ attr_reader :container
7
+
8
+ def initialize(container)
9
+ @container = container
10
+ end
11
+
12
+ def define(identifier, &block)
13
+ container.register(identifier, container[:transaction].define(&block))
14
+ end
15
+ end
16
+
17
+ def self.define(&block)
18
+ yield(Registrar.new(Container))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'rodakase/view'
2
+ require_relative 'container'
3
+
4
+ module Main
5
+ class Page
6
+ def title
7
+ 'Woohaa'
8
+ end
9
+ end
10
+ end
11
+
12
+ module Main
13
+ class View < Rodakase::View::Layout
14
+ setting :root, Container.root.join('web/templates')
15
+ setting :scope, Page.new
16
+ setting :engine, :slim
17
+ setting :name, 'app'.freeze
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Entities
2
+ User = Struct.new(:id, :name)
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'main/import'
2
+ require 'entities/user'
3
+
4
+ module Persistence
5
+ module Repositories
6
+ class Users
7
+ include Main::Import(:db)
8
+
9
+ def all
10
+ db[:users]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'rodakase/transaction'
2
+
3
+ class Transaction
4
+ def success(*args)
5
+ Rodakase::Transaction.Success(*args)
6
+ end
7
+
8
+ def failure(*args)
9
+ Rodakase::Transaction.Failure(*args)
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'main/import'
2
+ require 'entities/user'
3
+ require 'transaction'
4
+
5
+ module Transactions
6
+ class RegisterUser < Transaction
7
+ include Main::Import(:db)
8
+
9
+ def call(params)
10
+ if params['name']
11
+ success(db[:users] << Entities::User.new(*params.values_at('id', 'name')))
12
+ else
13
+ failure(:validation, 'name is missing')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ require 'main/view'
2
+
3
+ module Views
4
+ module Users
5
+ class Index < Main::View
6
+ configure do |config|
7
+ config.template = 'users/index'
8
+ end
9
+
10
+ def locals(options)
11
+ { users: [{ name: 'Jane' }, { name: 'Joe' }] }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ Main::Requests.define do |r|
2
+ r.define('requests.users.create') do
3
+ step 'transactions.register_user'
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ class Main::Application < Rodakase::Application
2
+ route('users') do |r|
3
+ r.get(to: 'views.users.index')
4
+
5
+ r.resolve('requests.users.create') do |t|
6
+ r.post do
7
+ t.(r[:user]) do |m|
8
+ m.success do
9
+ response.status = 201
10
+ end
11
+
12
+ m.failure do |err|
13
+ err.on(:validation) do |v|
14
+ r.redirect '/users'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end