femto 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a93cec4c12adeba287bb64b1d4a48ce9efcd0ab6
4
+ data.tar.gz: 92011f12f45c0e25e8ecb410b1d08cf388acde05
5
+ SHA512:
6
+ metadata.gz: 05f1be7d809186c663ab14b379a19c24e4e61b07444054efdf201cc9e2b5238f1d91e36cbd909a23aac7be8d6d5f5ec345e7848360965968534a8b2eceacb861
7
+ data.tar.gz: 6643c3a350cd4b85241a575d345f470af049274c1264278c052eb4b8c4b07d14a4bb224a0244c8f1329394eefa1881d6619fd3d1a85f07523b7840d98d15fc8f
data/.gitignore ADDED
@@ -0,0 +1,23 @@
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
+
19
+ # RubyMine
20
+ .idea/
21
+
22
+ # Random commands
23
+ build.command
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in femto.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 August
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,126 @@
1
+ # Femto
2
+
3
+ A tiny web framework.
4
+
5
+ ## Installation
6
+
7
+ Add this to your Gemfile:
8
+ ```ruby
9
+ gem 'femto', github: 'augustt198/femto'
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ First, setup your views/templates folder:
15
+
16
+ ```ruby
17
+ # For example
18
+ @templates_dir = File.join __dir__, 'views'
19
+ ```
20
+
21
+ Handle requests by passing a path and block to a HTTP verb method.
22
+
23
+ ```ruby
24
+ get '/' do
25
+ render 'home'
26
+ end
27
+
28
+ # The 'view' option automatically renders a template!
29
+ get '/about', view: 'about_page' do
30
+ # You can create variables to use in your views
31
+ @copyright_date = '2014'
32
+ end
33
+ ```
34
+
35
+ The render method tries to render a view if a String is passed, but other
36
+ content types can be rendered:
37
+ ```ruby
38
+ get '/status' do
39
+ render json: {system_status: 'good'}
40
+ end
41
+ ```
42
+
43
+ ### Models
44
+ To use models, first you need specify the model adapter. `MongoAdapter` is the only model adapter currently:
45
+
46
+ ```ruby
47
+ # Connect to database
48
+ Femto::Model::MongoAdapter.connect host: 'localhost', port: 27107, db: 'test'
49
+ Femto::Model.adapter = Femto::Model::MongoAdapter
50
+ ```
51
+
52
+ Add models with the `model` method, for example:
53
+ ```ruby
54
+ model :user do |m|
55
+ m.field :username
56
+ m.field :password
57
+ m.field :created_at
58
+ end
59
+ ```
60
+
61
+ This will create the class `User`. Use the model class to find, update, and insert:
62
+ ```ruby
63
+ user = User.new(username: 'foo', password: 'bar')
64
+ user.save # Saves to database or updates if it already exists
65
+ User.find # => [#<User:0x007fcb5bef8840>]
66
+ ```
67
+
68
+ The parameter passed to the block in the `model` method is the `ModelCreator`.
69
+ You can add your own methods to the model:
70
+ ```ruby
71
+ model :user do |m|
72
+ m.set_method('confirmed?') { false }
73
+ end
74
+ ```
75
+
76
+ You can also change the storage name of the model. The default is the model name + "s".
77
+ ```ruby
78
+ model :category do |m|
79
+ m.storage :categories
80
+ end
81
+ ```
82
+
83
+ ### Layouts
84
+
85
+ You can define application-wide views by using the layout method.
86
+ ```ruby
87
+ layout view: 'layout' do
88
+ # This block would be called every page load
89
+ end
90
+ ```
91
+
92
+ An example layout view:
93
+ ```html
94
+ <div class="container">
95
+ <!-- the yield keyword renders the current view -->
96
+ <%= yield %>
97
+ </div>
98
+ ```
99
+
100
+ ### Custom Renderers
101
+ Femto comes with the renderers `:json`, `:pretty_json`, and `:text`, but you can easily
102
+ add custom renderers.
103
+
104
+
105
+ For instance:
106
+ ```ruby
107
+ Femto::Renderer.renderer :custom do |content|
108
+ ['text/plain', content.to_s.reverse]
109
+ end
110
+ ```
111
+
112
+ All renderers should return an array with the `Content-Type` at position `[0]`, and the actual content
113
+ at position `[1]`.
114
+
115
+ ### [App Example](https://github.com/augustt198/femto/tree/master/example)
116
+
117
+ ## Contributing
118
+
119
+ 1. Fork it
120
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
121
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
122
+ 4. Push to the branch (`git push origin my-new-feature`)
123
+ 5. Create new Pull Request
124
+
125
+
126
+ _femto_ is the SI prefix for 10<sup>-15</sup>
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/example/App.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'femto'
2
+
3
+ class App < Femto::Base
4
+
5
+ @template_dir = File.join(__dir__, 'views')
6
+
7
+ layout view: 'layout'
8
+
9
+ # Set up database
10
+ Femto::Model::MongoAdapter.connect host: 'localhost', port: 27017, db: 'testing'
11
+ Femto::Model.adapter = Femto::Model::MongoAdapter
12
+
13
+ model :user do |m|
14
+ m.field :password
15
+ m.field :username
16
+ m.field :created_at
17
+ m.set_method('confirmed?') { 42 }
18
+ end
19
+
20
+ get '/', view: 'home' do
21
+ @time = Time.now
22
+ @number = rand 1000
23
+ end
24
+
25
+ get '/json' do
26
+ json = {features: {json_rendering: true}}
27
+ render pretty_json: json
28
+ end
29
+
30
+ get '/new_user' do
31
+ user = User.new
32
+ user.username = 'username_goes_here'
33
+ user.password = 'password_goes_here'
34
+ render text: 'User created'
35
+ end
36
+
37
+ get '/list_users' do
38
+ users = User.find
39
+ results = []
40
+ users.each { |u| results << u.inspect }
41
+ render pretty_json: {users: results}
42
+ end
43
+
44
+ end
data/example/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ require './app'
2
+ run App
@@ -0,0 +1,2 @@
1
+ %h1= 'The current time is ' + @time.to_s
2
+ %h2= 'Random number: ' + @number.to_s
@@ -0,0 +1,11 @@
1
+ %head
2
+ %title Yet another web microframework!
3
+ %body
4
+ .container
5
+ = yield
6
+
7
+ :css
8
+ .container {
9
+ margin: 50px;
10
+ font-family: 'Helvetica Neue', 'Helvetica', sans-serif;
11
+ }
data/femto.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'femto/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "femto"
8
+ spec.version = Femto::VERSION
9
+ spec.authors = ["August"]
10
+ spec.email = ["augustt198@gmail.com"]
11
+ spec.description = %q{A tiny web framework}
12
+ spec.summary = %q{A tiny web framework}
13
+ spec.homepage = ""
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_dependency 'rack', '~> 1.4.5'
24
+ spec.add_dependency 'tilt', '~> 2.0.1'
25
+ spec.add_dependency 'haml', '~> 4.0.4'
26
+ spec.add_dependency 'mongo', '~> 1.10.0'
27
+ spec.add_dependency 'bson_ext', '~> 1.10.0'
28
+ end
data/lib/femto.rb ADDED
@@ -0,0 +1,144 @@
1
+ require 'femto/version'
2
+ require 'femto/renderer'
3
+ require 'femto/model'
4
+ require 'tilt'
5
+ require 'rack'
6
+ require 'json'
7
+
8
+ module Femto
9
+
10
+ class Base
11
+ class << self
12
+
13
+ attr_accessor :request, :response, :env, :routes, :template_dir,
14
+ :render, :content_type, :layout, :layout_block
15
+
16
+ # set up methods
17
+ %w(get post patch put delete).each do |http_verb|
18
+ define_method http_verb do |path, options={}, &block|
19
+ set_route http_verb, path, options, block
20
+ end
21
+ end
22
+
23
+ def layout(options={}, &block)
24
+ if options[:template]
25
+ @layout = resolve_template options[:template]
26
+ elsif options[:view]
27
+ @layout = resolve_template options[:view]
28
+ end
29
+ @layout_block = block
30
+ end
31
+
32
+ def set_route(verb, path, options, block)
33
+ @routes = {} unless @routes
34
+ @routes[verb] = [] unless @routes[verb]
35
+ @routes[verb] << [path, options, block]
36
+ end
37
+
38
+ def handle_request
39
+ catch :stop do
40
+ verb = request.request_method.downcase
41
+ request_path = request.path_info
42
+ routes = @routes[verb]
43
+ if routes
44
+ routes.each do |group|
45
+ path = group[0]
46
+ options = group[1]
47
+ block = group[2]
48
+ if request_path == path
49
+ instance_eval(&block)
50
+ if options[:template]
51
+ render options[:template]
52
+ elsif options[:view]
53
+ render options[:view]
54
+ end
55
+ if @layout and @content_type == 'text/html'
56
+ if @layout_block
57
+ @layout_block.call
58
+ end
59
+ @render = render_template(@layout) { @render }
60
+ end
61
+ if @render == nil
62
+ raise TemplateMissingException.new
63
+ end
64
+ response.write @render
65
+ response['Content-Type'] = content_type
66
+ return
67
+ end
68
+ end
69
+ end
70
+ stop
71
+ end
72
+ end
73
+
74
+ def render(options)
75
+ if options.is_a? Hash
76
+ pair = options.to_a[0]
77
+ type = pair[0]
78
+ content = pair[1]
79
+ render_pair = Femto::Renderer.render(type, content)
80
+ @content_type = render_pair[0]
81
+ @render = render_pair[1]
82
+ elsif options.is_a? String
83
+ @render = render_template(resolve_template(options))
84
+ end
85
+ end
86
+
87
+ def model(name, &block)
88
+ Femto::Model.create_model name.to_s, &block
89
+ end
90
+
91
+ def resolve_template(file)
92
+ Dir[File.join(@template_dir, file + '.*')][0]
93
+ end
94
+
95
+ def render_template(template, &block)
96
+ @content_type = 'text/html'
97
+ Tilt.new(template).render self, {}, &block
98
+ end
99
+
100
+ def stop
101
+ throw :stop
102
+ end
103
+
104
+ def builder
105
+ @builder = Rack::Builder.new unless @builder
106
+ @builder
107
+ end
108
+
109
+ def call(env)
110
+ dup.call! env
111
+ end
112
+
113
+ def call!(env)
114
+ env['PATH_INFO'] = '/' if env['PATH_INFO'].empty?
115
+ @request = Rack::Request.new env
116
+ @response = Rack::Response.new
117
+ @render = nil
118
+ @content_type = nil
119
+ @env = env
120
+ handle_request
121
+ @response.finish
122
+ end
123
+
124
+ end
125
+
126
+ class TemplateMissingException < Exception
127
+ def initialize
128
+ super 'No template to be rendered was found'
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+ class RequestException < Exception
135
+ attr_reader :code
136
+ attr_reader :message
137
+ def initialize(code, msg)
138
+ super "#{code}: #{msg}"
139
+ @code = code
140
+ @message = msg
141
+ end
142
+ end
143
+
144
+ end
@@ -0,0 +1,143 @@
1
+ require 'femto/model/mongo_adapter'
2
+
3
+ module Femto
4
+
5
+ module Model
6
+
7
+ class << self
8
+ attr_accessor :adapter
9
+ end
10
+
11
+ def self.create_model(name, &block)
12
+ class_name = camelize name
13
+ begin
14
+ Object.const_get class_name
15
+ return # Class already exists
16
+ rescue NameError
17
+ # ignored
18
+ end
19
+ model_creator = ModelCreator.new
20
+ block.call model_creator
21
+
22
+ # Create class
23
+ model_class = Class.new &model_creator.class_opts
24
+ Object.const_set(class_name, model_class)
25
+
26
+ # Create accessors for attributes
27
+ model_creator.fields.each do |a|
28
+ model_class.module_eval { attr_accessor a }
29
+ end
30
+ model_class.module_eval { attr_accessor :id }
31
+
32
+ # Add custom methods
33
+ model_creator.custom_methods.each_pair do |method_name, method_block|
34
+ model_class.module_eval { define_method method_name, &method_block }
35
+ end
36
+
37
+ # Add model methods
38
+ model_class.define_singleton_method 'find' do |query={}|
39
+ Model.adapter.find(model_class, query)
40
+ end
41
+ model_class.define_singleton_method 'where' do |query={}|
42
+ Model.adapter.find(model_class, query)
43
+ end
44
+ model_class.define_singleton_method 'create' do |fields={}|
45
+ model = model_class.new fields
46
+ model.save
47
+ model
48
+ end
49
+ model_class.define_singleton_method 'all' do
50
+ model_class.find
51
+ end
52
+
53
+ model_class.module_eval do
54
+ define_method 'update' do
55
+ Model.adapter.update self
56
+ end
57
+
58
+ define_method 'save' do
59
+ Model.adapter.update self
60
+ end
61
+
62
+ define_method('remove') { Model.adapter.remove self }
63
+ define_method('delete') { Model.adapter.remove self }
64
+
65
+ define_method 'to_hash' do
66
+ result = {}
67
+ self.class.model_attrs[:fields].each do |f|
68
+ val = send f
69
+ result[f] = val if val
70
+ end
71
+ result
72
+ end
73
+
74
+ define_method 'initialize' do |fields={}|
75
+ fields.each_pair do |key, val|
76
+ next unless self.class.model_attrs[:fields].include? key
77
+ send key.to_s + '=', val
78
+ end
79
+ end
80
+ end
81
+
82
+ # Model attributes (fields, storage, etc...)
83
+ class << model_class
84
+ attr_accessor :model_attrs
85
+ end
86
+ storage = model_creator.storage_name ? model_creator.storage_name.to_s : name + 's'
87
+ model_class.model_attrs = {
88
+ fields: model_creator.fields,
89
+ storage_name: storage
90
+ }
91
+
92
+ # Create method for getting defined fields
93
+ model_class.define_singleton_method('fields') { model_creator.fields }
94
+ end
95
+
96
+ class ModelCreator
97
+ attr_accessor :fields
98
+ attr_accessor :defaults
99
+ attr_accessor :types
100
+ attr_accessor :class_opts
101
+ attr_accessor :custom_methods
102
+ attr_accessor :storage_name
103
+
104
+ def initialize
105
+ @fields = []
106
+ @defaults = {}
107
+ @types = {}
108
+ @custom_methods = {}
109
+ end
110
+
111
+ def field(name, options={})
112
+ return unless name
113
+ fields << name
114
+ if options[:default]
115
+ defaults[name]
116
+ end
117
+ end
118
+
119
+ def class_options(&block)
120
+ @class_opts = block
121
+ end
122
+
123
+ def set_method(name, &block)
124
+ custom_methods[name] = block
125
+ end
126
+
127
+ def storage(name)
128
+ @storage_name = name
129
+ end
130
+ end
131
+
132
+ # Taken from http://infovore.org/archives/2006/08/11/writing-your-own-camelizer-in-ruby/
133
+ def self.camelize(snake_case, first_upcase=true)
134
+ if first_upcase
135
+ snake_case.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
136
+ else
137
+ snake_case.first + camelize(snake_case)[1..-1]
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,69 @@
1
+ require 'mongo'
2
+
3
+ module Femto
4
+ module Model
5
+ class MongoAdapter
6
+ class << self
7
+
8
+ attr_accessor :client
9
+ attr_accessor :db
10
+
11
+ def connect(options=nil)
12
+ if options
13
+ @client = Mongo::Connection.new(options[:host], options[:port])
14
+ @db = @client[options[:db]]
15
+ else
16
+ @client = Mongo::Connection.new
17
+ @db = @client['test']
18
+ end
19
+ end
20
+
21
+ def to_hash(model)
22
+ result = {}
23
+ model.class.model_attrs[:fields].each do |f|
24
+ var = model.send f
25
+ result[f] = var if var
26
+ end
27
+ result
28
+ end
29
+
30
+ def find(cls, query)
31
+ results = []
32
+ get_coll(cls).find(query).each do |res|
33
+ model = cls.new(symbolize_keys(res))
34
+ model.id = res['_id']
35
+ results << model
36
+ end
37
+ results
38
+ end
39
+
40
+ def update(model)
41
+ coll = get_coll model.class
42
+ if model.id
43
+ coll.update({:_id => model.id}, model.to_hash)
44
+ else
45
+ model.id = coll.insert model.to_hash
46
+ end
47
+ end
48
+
49
+ def remove(model)
50
+ coll = get_coll model.class
51
+ if model.id
52
+ coll.remove(:_id => model.id)
53
+ end
54
+ end
55
+
56
+ def get_coll(cls)
57
+ @db[cls.model_attrs[:storage_name]]
58
+ end
59
+
60
+ def symbolize_keys(hash)
61
+ hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+
3
+ module Femto
4
+
5
+ module Renderer
6
+
7
+ @renderers = {}
8
+
9
+ def self.render(type, content)
10
+ renderer = @renderers[type]
11
+ raise RendererNotFoundException.new('No renderer for type ' + type.inspect) unless renderer
12
+ renderer.call content
13
+ end
14
+
15
+ def self.renderer(type, &block)
16
+ @renderers[type] = block
17
+ end
18
+
19
+ # Setup default renderers
20
+ renderer(:json) { |c| ['application/json', c.to_json] }
21
+ renderer(:pretty_json) { |c| ['application/json', JSON.pretty_generate(c)] }
22
+ renderer(:text) { |c| ['text/plain', c.to_s] }
23
+
24
+ class RendererNotFoundException < Exception
25
+ def initialize(reason)
26
+ super reason
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,3 @@
1
+ module Femto
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: femto
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - August
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.5
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.5
55
+ - !ruby/object:Gem::Dependency
56
+ name: tilt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: haml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 4.0.4
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 4.0.4
83
+ - !ruby/object:Gem::Dependency
84
+ name: mongo
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.10.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.10.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: bson_ext
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.10.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.10.0
111
+ description: A tiny web framework
112
+ email:
113
+ - augustt198@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - example/App.rb
124
+ - example/config.ru
125
+ - example/views/home.haml
126
+ - example/views/layout.haml
127
+ - femto.gemspec
128
+ - lib/femto.rb
129
+ - lib/femto/model.rb
130
+ - lib/femto/model/mongo_adapter.rb
131
+ - lib/femto/renderer.rb
132
+ - lib/femto/version.rb
133
+ homepage: ''
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.2.0.rc.1
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: A tiny web framework
157
+ test_files: []