grass 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.sass-cache/e3d4c2039fc7a8446e752aad5ac08f85d7457f92/(__TEMPLATE__)c +0 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +10 -0
  9. data/bin/grass +89 -0
  10. data/config/grass.rb +27 -0
  11. data/db/migrate/1_create_grass_sources.rb +24 -0
  12. data/grass.gemspec +43 -0
  13. data/lib/grass.rb +68 -0
  14. data/lib/grass/cache.rb +52 -0
  15. data/lib/grass/core_ext/kernel.rb +8 -0
  16. data/lib/grass/endpoints/api.rb +70 -0
  17. data/lib/grass/endpoints/front.rb +122 -0
  18. data/lib/grass/file_sync.rb +70 -0
  19. data/lib/grass/goliath/rack/auth_barrier.rb +109 -0
  20. data/lib/grass/goliath/rack/cache.rb +37 -0
  21. data/lib/grass/goliath/rack/cors.rb +45 -0
  22. data/lib/grass/goliath/rack/secure_headers.rb +20 -0
  23. data/lib/grass/goliath/rack/validator.rb +52 -0
  24. data/lib/grass/helpers/i18n_helper.rb +91 -0
  25. data/lib/grass/helpers/render_helper.rb +35 -0
  26. data/lib/grass/key.rb +137 -0
  27. data/lib/grass/render.rb +27 -0
  28. data/lib/grass/render/layout.rb +11 -0
  29. data/lib/grass/render/page.rb +31 -0
  30. data/lib/grass/render/renderer.rb +35 -0
  31. data/lib/grass/render/script.rb +27 -0
  32. data/lib/grass/render/stylesheet.rb +13 -0
  33. data/lib/grass/render/text.rb +11 -0
  34. data/lib/grass/render/view.rb +34 -0
  35. data/lib/grass/render/yui_renderer.rb +27 -0
  36. data/lib/grass/source.rb +107 -0
  37. data/lib/grass/tasks/db.rake +67 -0
  38. data/lib/grass/version.rb +3 -0
  39. data/lib/templates/app/Gemfile +9 -0
  40. data/lib/templates/app/Procfile +3 -0
  41. data/lib/templates/app/Rakefile +7 -0
  42. data/lib/templates/app/app/assets/scripts/application.en.js.coffee +1 -0
  43. data/lib/templates/app/app/assets/stylesheets/application.en.css.scss +4 -0
  44. data/lib/templates/app/app/content/pages/about.en.html.erb +3 -0
  45. data/lib/templates/app/app/content/pages/index.en.md.erb +5 -0
  46. data/lib/templates/app/app/views/layouts/application.en.html.erb +14 -0
  47. data/lib/templates/app/app/views/pages/show.en.html.erb +4 -0
  48. data/lib/templates/app/app/views/shared.en.html.erb +9 -0
  49. data/lib/templates/app/config/cache.yml +20 -0
  50. data/lib/templates/app/config/database.yml +35 -0
  51. data/lib/templates/app/config/grass.rb +27 -0
  52. data/lib/templates/app/db/migrate/1_create_grass_sources.rb +24 -0
  53. data/lib/templates/app/haproxy.cfg +43 -0
  54. data/lib/templates/app/public/favicon.ico +0 -0
  55. data/lib/templates/app/public/robots.txt +2 -0
  56. data/lib/templates/app/server.rb +7 -0
  57. data/test/dummy/app/content/texts/testapi.en.txt +1 -0
  58. data/test/dummy/config/cache.yml +23 -0
  59. data/test/dummy/config/database.yml +35 -0
  60. data/test/dummy/config/dummy.rb +1 -0
  61. data/test/dummy/config/haproxy.cfg +37 -0
  62. data/test/dummy/public/favicon.ico +0 -0
  63. data/test/dummy/public/robots.txt +2 -0
  64. data/test/minitest_helper.rb +38 -0
  65. data/test/support/grass.rb +21 -0
  66. data/test/support/test.jpg +0 -0
  67. data/test/test_api.rb +74 -0
  68. data/test/test_front.rb +52 -0
  69. data/test/test_key.rb +118 -0
  70. data/test/test_source.rb +51 -0
  71. data/test/test_source_file.rb +47 -0
  72. data/test/test_source_render.rb +54 -0
  73. data/vendor/yuicompressor-2.4.8.jar +0 -0
  74. metadata +399 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b327dd07017b0b13990495f3e6f3bd103249c77b
4
+ data.tar.gz: d77ae3d10091e19e1ac888f1861916840f82a5ec
5
+ SHA512:
6
+ metadata.gz: 8666b49f18e2f7140f90492bb082c19012b2097ce322cf3f631453940acf0ad62c89e49a244285844d07c3c2770f552e589975614349c0134665029259a1e5ba
7
+ data.tar.gz: 73af1d28ef19ab0c6a33784d93d437bcecf95aed34b844bd3e4b919d37425d4b88bbde17c87118929f737c449682300e5d26a1bd3bc22a1dccae8c2fab7123e1
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in grass.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Onur Uyar
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.
@@ -0,0 +1,29 @@
1
+ # Grass
2
+
3
+ Yet another ruby framework
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'grass'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install grass
18
+
19
+ ## Usage
20
+
21
+ to create new app : `grass new PATHNAME`
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/grass/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ end
7
+
8
+ task :default => :test
9
+
10
+ load "lib/grass/tasks/db.rake"
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ $stdout.sync = true
5
+
6
+ require 'commander/import'
7
+ require 'fileutils'
8
+ require 'grass'
9
+ require 'grass/key'
10
+ require 'grass/source'
11
+
12
+ # :name is optional, otherwise uses the basename of this executable
13
+ program :name, 'Grass CLI'
14
+ program :version, '0.0.1'
15
+ program :description, 'Grass CLI'
16
+
17
+ command :new do |c|
18
+ c.syntax = 'grass new PATH'
19
+ c.description = 'Creates new Grass app'
20
+ c.action do |args, options|
21
+ path = args.first
22
+ FileUtils.mkdir_p path
23
+ template_root = "#{Grass.gem_root}/lib/templates"
24
+ FileUtils.cp_r "#{template_root}/app/.", path
25
+ ["#{path}/config/database.yml","#{path}/config/cache.yml"].each do |filepath|
26
+ content = ::File.read(filepath)
27
+ content.gsub!(/\$app/m,path.split("/").last)
28
+ content.gsub!(/\$username/m,ENV['USER']||"postgres")
29
+ ::File.open(filepath,::File::RDWR){|f| f.truncate(0); f.rewind; f.write(content) }
30
+ end
31
+ puts "Grass app created on #{path}"
32
+ end
33
+ end
34
+
35
+ command :push do |c|
36
+
37
+ c.syntax = 'grass push'
38
+ c.description = 'creates db objects from files'
39
+ c.action do |args, options|
40
+ require "#{Grass.root}/config/grass"
41
+ files = Dir.glob("#{Grass.app_root}/**/*")
42
+
43
+ Grass.cache.flush
44
+
45
+ files.delete_if{|file| file =~ /\/helpers\//}.each do |file|
46
+
47
+ unless File.directory?(file)
48
+ source = Grass::Source.find_or_create_by!(filepath: file)
49
+ source.raw = File.read(file)
50
+ source.commit!
51
+ say "Pushed File: #{source.filepath}"
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ command :pull do |c|
60
+ c.syntax = 'grass pull'
61
+ c.description = 'Transfers file data'
62
+ c.option '--from ENV', String, 'source ENV, default production'
63
+ c.option '--to ENV', String, 'target ENV, default development'
64
+ c.action do |args, options|
65
+ options.default from: 'production', to: 'development'
66
+
67
+ config = YAML.load(ERB.new(File.read('config/database.yml')).result)
68
+ ActiveRecord::Base.establish_connection config[options.from]
69
+ files = Grass::Source.all.as_json
70
+ ActiveRecord::Base.remove_connection
71
+
72
+ ActiveRecord::Base.establish_connection config[options.to]
73
+ files.each do |file|
74
+ source = Grass::Source.find_or_initialize_by(filepath: file["filepath"].dup)
75
+ source.raw = file["raw"]
76
+ source.filepath = file["filepath"]
77
+ source.handler = file["handler"]
78
+ source.format = file["format"]
79
+ source.commit!
80
+ say "Pulled File: #{source.filepath}"
81
+ end
82
+
83
+ config = YAML::load(ERB.new(::File.read("#{Grass.root}/config/cache.yml")).result)[options.to]
84
+ dalli = Dalli::Client.new(config.delete("servers").split(","), config)
85
+ dalli.flush
86
+
87
+ end
88
+ end
89
+
@@ -0,0 +1,27 @@
1
+ require 'i18n'
2
+ require 'grass'
3
+ require 'ip_country'
4
+ require 'active_record'
5
+
6
+ Time.zone = ENV['TIME_ZONE'] || "London"
7
+ I18n.load_path << Dir.glob("#{Grass.root}/config/locales/**/*.yml")
8
+ I18n.enforce_available_locales = false
9
+ I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
10
+ I18n.default_locale = ENV['DEFAULT_LOCALE'] ? ENV['DEFAULT_LOCALE'].to_sym : :en
11
+ I18n.available_locales = ENV['AVAILABLE_LOCALES'] ? ENV['AVAILABLE_LOCALES'].split(",").map(&:to_sym) : [:en]
12
+
13
+ ActiveRecord::Base.establish_connection Grass.load_config('database')
14
+
15
+ if respond_to?(:config)
16
+
17
+ # config['enable_cache_for_development'] = true
18
+
19
+ ENV['GEOIP_FILE'] ||= "#{Grass.root}/db/geo_ip.dat"
20
+ if ::File.exists?(ENV['GEOIP_FILE'])
21
+ IPCountry.init ENV['GEOIP_FILE']
22
+ config['ip_country'] = IPCountry
23
+ end
24
+
25
+ config['dalli'] = Grass.cache
26
+
27
+ end
@@ -0,0 +1,24 @@
1
+ class CreateGrassSources < ActiveRecord::Migration
2
+ def change
3
+ create_table :grass_sources, id: false do |t|
4
+ t.column :keyid, :string, null: false, index: true, primary: true
5
+ t.column :dir, :string
6
+ t.column :path, :string
7
+ t.column :locale, :string
8
+ t.column :format, :string
9
+ t.column :handler, :string
10
+ t.column :filepath, :string
11
+
12
+ t.column :raw, :text
13
+ t.column :result, :text
14
+ t.column :binary, :oid, limit: 2147483648 #:binary
15
+
16
+ t.column :pairs, :string, default: []
17
+ t.column :hidden, :boolean, default: false
18
+ t.column :mime_type, :string
19
+
20
+ t.timestamps
21
+ end
22
+ add_index :grass_sources, [:locale,:dir,:path], unique: true
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'grass/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "grass"
8
+ spec.version = Grass::VERSION
9
+ spec.authors = ["Onur Uyar"]
10
+ spec.email = ["me@onuruyar.com"]
11
+ spec.summary = %q{Yet another ruby framework}
12
+ spec.homepage = "http://github.com/lemmycaution/grass"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "sqlite3"
24
+ spec.add_development_dependency 'em-http-request'
25
+
26
+ spec.add_dependency "pg"
27
+ spec.add_dependency "i18n"
28
+ spec.add_dependency "activerecord"
29
+
30
+ spec.add_dependency "tilt"
31
+ spec.add_dependency "sass"
32
+ spec.add_dependency "coffee-script"
33
+ spec.add_dependency "yui-compressor"
34
+ spec.add_dependency "uglifier"
35
+ spec.add_dependency "redcarpet"
36
+ spec.add_dependency "mime-types"
37
+
38
+ spec.add_dependency 'goliath'
39
+ spec.add_dependency "ip_country"
40
+ spec.add_dependency "dalli"
41
+
42
+ spec.add_dependency "commander"
43
+ end
@@ -0,0 +1,68 @@
1
+ require "grass/version"
2
+ require "grass/core_ext/kernel"
3
+ require 'pathname'
4
+ require 'dalli'
5
+ require 'erb'
6
+ require 'yaml'
7
+ require 'active_support/core_ext/hash'
8
+
9
+ module Grass
10
+
11
+ class << self
12
+
13
+ def gem_root
14
+ @@gemroot ||= File.expand_path('../..', __FILE__)
15
+ end
16
+
17
+ def root
18
+ @@root ||= find_root_with_flag("Procfile", Dir.pwd).to_s
19
+ end
20
+
21
+ def root= root
22
+ @@root = root
23
+ end
24
+
25
+ def app_root
26
+ @@app_root ||= "#{self.root}/app".gsub("//","/")
27
+ end
28
+
29
+ def cache
30
+ $cache ||= begin
31
+ config = self.load_config('cache')
32
+ Dalli::Client.new config.delete("servers").split(","), config.symbolize_keys!
33
+ end
34
+ end
35
+
36
+ def cache=cache
37
+ $cache = cache
38
+ end
39
+
40
+ def env
41
+ ENV['RACK_ENV'] ||= "development"
42
+ end
43
+
44
+ def load_config file
45
+ db_conf = YAML.load(ERB.new(File.read("#{Grass.root}/config/#{file}.yml")).result)[self.env]
46
+ end
47
+
48
+ end
49
+
50
+ private
51
+
52
+ # i steal this from rails
53
+ def self.find_root_with_flag(flag, default=nil)
54
+ root_path = self.class.called_from[0]
55
+
56
+ while root_path && ::File.directory?(root_path) && !::File.exist?("#{root_path}/#{flag}")
57
+ parent = ::File.dirname(root_path)
58
+ root_path = parent != root_path && parent
59
+ end
60
+
61
+ root = ::File.exist?("#{root_path}/#{flag}") ? root_path : default
62
+ raise "Could not find root path for #{self}" unless root
63
+
64
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
65
+ Pathname.new(root).expand_path : Pathname.new(root).realpath
66
+ end
67
+
68
+ end
@@ -0,0 +1,52 @@
1
+ module Grass
2
+ module Cache
3
+
4
+ DATA_CACHE_KEYS = %i(language_info country_info params http_host request_path)
5
+
6
+ module ClassMethods
7
+
8
+ def read_cache cache_key
9
+ JSON.load(Grass.cache.get(cache_key))
10
+ end
11
+
12
+ def generate_cachekey key_fullpath, data
13
+ Digest::MD5.hexdigest("#{key_fullpath}_#{data.select{|k,v| DATA_CACHE_KEYS.include?(k)}}")
14
+ end
15
+
16
+ end
17
+
18
+ def self.included(base)
19
+ base.extend ClassMethods
20
+ base.send :after_destroy, :clear_cache
21
+ end
22
+
23
+ def commit! result = nil
24
+ # clear_cache if precompile?
25
+ super(result)
26
+ set_cache if precompile?
27
+ self
28
+ end
29
+
30
+ def cache!
31
+ set_cache
32
+ end
33
+
34
+ def precompile?
35
+ self.binary.nil? && (self.type == "script" || self.type == "stylesheet")
36
+ end
37
+
38
+ module_function
39
+
40
+ def set_cache
41
+ Grass.cache.set(
42
+ self.class.generate_cachekey(self.key.fullpath,self.data),
43
+ JSON.dump([self.mime_type, self.read].flatten)
44
+ )
45
+ end
46
+
47
+ def clear_cache
48
+ Grass.cache.delete self.class.generate_cachekey(self.key.fullpath,self.data) rescue nil
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,8 @@
1
+ module Kernel
2
+
3
+ def called_from(level=1)
4
+ arrs = caller((level||1)+1) or return
5
+ arrs[0] =~ /:(\d+)(?::in `(.*)')?/ ? [$`, $1.to_i, $2] : nil
6
+ end
7
+
8
+ end
@@ -0,0 +1,70 @@
1
+ require 'goliath/api'
2
+ require 'json'
3
+ require 'grass'
4
+ require 'grass/source'
5
+ require 'grass/goliath/rack/secure_headers'
6
+
7
+ module Grass
8
+
9
+ class API < Goliath::API
10
+ use Goliath::Rack::SecureHeaders
11
+ use Goliath::Rack::Params
12
+ use Goliath::Rack::Render
13
+ use Goliath::Rack::Favicon, "#{Grass.root}/public/favicon.ico"
14
+
15
+ JSON_HEAD = {"Content-Type" => "application/json"}
16
+ FILE_PARAMS = %w(raw binary)
17
+ FILE_ACTIONS = %w(hide show commit)
18
+
19
+ def response(env)
20
+ self.public_send env['REQUEST_METHOD'].downcase, env
21
+ end
22
+
23
+ def get(env)
24
+ [200,JSON_HEAD,get_file.to_json]
25
+ end
26
+
27
+ def post(env)
28
+ file = Source.create(get_file_params.update(key: env['REQUEST_PATH']))
29
+ error! file unless file.persisted?
30
+ get_file_actions.each{|action| file.public_send(action) }
31
+ [200,JSON_HEAD,file.to_json]
32
+ end
33
+
34
+ def put(env)
35
+ file = get_file
36
+ updated = file.update(get_file_params)
37
+ error! file unless updated
38
+ get_file_actions.each{|action| file.public_send(action) }
39
+ [200,JSON_HEAD,file.to_json]
40
+ end
41
+
42
+ def delete(env)
43
+ file = get_file
44
+ deleted = !file.destroy.persisted?
45
+ error! file unless deleted
46
+ [200,JSON_HEAD,deleted]
47
+ end
48
+
49
+ private
50
+
51
+ def get_file
52
+ raise Goliath::Validation::NotFoundError unless file = Source[env['REQUEST_PATH']].first
53
+ file
54
+ end
55
+
56
+ def get_file_actions
57
+ FILE_ACTIONS.select{ |action| params.delete(action) }.map{|action| "#{action}!" }
58
+ end
59
+
60
+ def get_file_params
61
+ params.select{ |key,value| FILE_PARAMS.include?(key) }
62
+ end
63
+
64
+ def error! file
65
+ raise Goliath::Validation::NotAcceptable.new(file.errors.full_messages.to_json)
66
+ end
67
+
68
+ end
69
+
70
+ end