alfa 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ module Alfa
2
+ class CliApplication
3
+
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Alfa
2
+ class Controller
3
+ def _instance_variables_hash
4
+ Hash[instance_variables.map { |name| [name.to_s[1..-1].to_sym, instance_variable_get(name)] } ]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,55 @@
1
+ require 'alfa/support'
2
+ require 'mysql2'
3
+
4
+ module Alfa
5
+ module Database
6
+ class MySQL
7
+ include Alfa::ClassInheritance
8
+ inheritable_attributes :host, :port, :user, :password, :dbname, :client
9
+ @host = nil
10
+ @port = 3306
11
+ @user = nil
12
+ @password = nil
13
+ @dbname = nil
14
+ @client = nil
15
+
16
+ def self.check_params
17
+ raise ":host must be defined for #{self.to_s}" unless @host
18
+ raise ":user must be defined for #{self.to_s}" unless @user
19
+ raise ":password must be defined for #{self.to_s}" unless @password
20
+ raise ":dbname must be defined for #{self.to_s}" unless @dbname
21
+ end
22
+
23
+ def self.query query
24
+ begin
25
+ self.client.query(query)
26
+ rescue Mysql2::Error => e
27
+ raise "#{e.message} (query: \"#{query}\", error number: #{e.error_number}, sql state: #{e.sql_state})"
28
+ end
29
+ end
30
+
31
+ def self.client
32
+ unless @client
33
+ self.check_params
34
+ @client = Mysql2::Client.new(:host=>@host, :username=>@user)
35
+ @client.query_options.merge!(:symbolize_keys => true, :as => :hash, :database_timezone => :utc, :application_timezone => :utc)
36
+ @client.query "SET NAMES utf8"
37
+ @client.query "USE #{@dbname}"
38
+ end
39
+ @client
40
+ end
41
+
42
+ def self.transaction &block
43
+ begin
44
+ self.query "START TRANSACTION"
45
+ yield
46
+ rescue
47
+ self.query "ROLLBACK"
48
+ else
49
+ self.query "COMMIT"
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1 @@
1
+ require 'alfa/database/mysql'
@@ -0,0 +1,4 @@
1
+ module Alfa
2
+ class RouteException404 < StandardError
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module Alfa
2
+ module Models
3
+ class Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'alfa/models/base'
2
+
3
+ module Alfa
4
+ module Models
5
+ class BaseSQL < Alfa::Models::Base
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Alfa
2
+ module Models
3
+ class Dummy
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ require 'alfa/support'
2
+ require 'alfa/database/mysql'
3
+ require 'alfa/models/base_sql'
4
+
5
+ module Alfa
6
+ module Models
7
+ class MySQL < Alfa::Models::BaseSQL
8
+ include Alfa::ClassInheritance
9
+ inheritable_attributes :connection, :table
10
+ @connection = nil
11
+ @table = nil
12
+ @pk = :id
13
+
14
+ def self.register_database database
15
+ raise 'Expected database to be instance of Alfa::Database::MySQL' unless database.ancestors.include? Alfa::Database::MySQL
16
+ @connection = database
17
+ end
18
+
19
+ #@return Array || nil
20
+ def self.all
21
+ @connection.query("SELECT * FROM `#{self.table}`")
22
+ end
23
+
24
+ def self.find filter = {}
25
+
26
+ end
27
+
28
+ def self.find_first filter = {}
29
+ end
30
+
31
+ def self.count filter = {}
32
+ end
33
+
34
+ def self.exists? pk
35
+ end
36
+
37
+ def self.create data = {}
38
+ end
39
+
40
+ def self.delete pk
41
+ end
42
+
43
+ def self.update data = {}
44
+ end
45
+
46
+ def self.table
47
+ @table.to_s
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,2 @@
1
+ require 'alfa/models/mysql'
2
+ require 'alfa/models/dummy'
@@ -0,0 +1,37 @@
1
+ module Alfa
2
+
3
+ # thanks to John
4
+ # http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/
5
+ module ClassInheritance
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def inheritable_attributes(*args)
12
+ @inheritable_attributes ||= [:inheritable_attributes]
13
+ @inheritable_attributes += args
14
+ args.each do |arg|
15
+ class_eval %(
16
+ class << self; attr_accessor :#{arg} end
17
+ )
18
+ end
19
+ @inheritable_attributes
20
+ end
21
+
22
+ def inherited(subclass)
23
+ @inheritable_attributes.each do |inheritable_attribute|
24
+ instance_var = "@#{inheritable_attribute}"
25
+ subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ class Support
32
+ def self.capitalize_name arg
33
+ arg.to_s.split('/').last.split('_').map(&:capitalize).join
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,121 @@
1
+ # coding: utf-8
2
+ require 'alfa/exceptions'
3
+ require 'ruty'
4
+ require 'ruty/tags/resources'
5
+
6
+ Encoding.default_external='utf-8'
7
+ Encoding.default_internal='utf-8'
8
+
9
+ module Alfa
10
+ class WebApplication
11
+
12
+ # main rack routine
13
+ def self.call env
14
+ @env = env
15
+ begin
16
+ response_code = 200
17
+ route, params = self.find_route
18
+ c_sym = route[:options].has_key?(:controller) ? route[:options][:controller] : params[:controller]
19
+ a_sym = route[:options].has_key?(:action) ? route[:options][:action] : params[:action]
20
+ l_sym = route[:options].has_key?(:layout) ? route[:options][:layout] : :default
21
+ controller = self.invoke_controller(c_sym)
22
+ raise Alfa::RouteException404 unless controller.public_methods.include?(a_sym)
23
+ controller.__send__(a_sym)
24
+ data = controller._instance_variables_hash
25
+ Ruty::Tags::RequireStyle.clean_cache
26
+ content = self.render_template(File.join(c_sym.to_s, a_sym.to_s + '.tpl'), data)
27
+ body = self.render_layout(l_sym.to_s + '.tpl', {body: content})
28
+ rescue Alfa::RouteException404
29
+ response_code = 404
30
+ body = 'Url not found'
31
+ rescue Exception => e
32
+ response_code = 500
33
+ body = 'Error occured: ' + e.message + ' at ' + e.backtrace.first
34
+ end
35
+ headers = {
36
+ "Content-Type" => 'text/html; charset=utf-8',
37
+ }
38
+ [response_code, headers, [body]]
39
+ end
40
+
41
+ # set routes
42
+ def self.routes &block
43
+ @routes = []
44
+ class_eval &block
45
+ end
46
+
47
+
48
+ def self.route rule, options = {}
49
+ @routes << {:rule => rule, :options => options}
50
+ end
51
+
52
+ private
53
+
54
+ def self.find_route
55
+ url = @env['PATH_INFO']
56
+ @routes.each do |route|
57
+ is_success, params = self.route_match? route[:rule], url
58
+ return route, params if is_success
59
+ end
60
+ raise Alfa::RouteException404
61
+ end
62
+
63
+
64
+ def self.route_match? rule, url
65
+ if rule.is_a? String
66
+ rule_trail_slash = rule[-1] == '/'
67
+ url_trail_slash = url[-1] == '/'
68
+ rule_segments = rule.split('/').reject(&:empty?)
69
+ url_segments = url.split('/').reject(&:empty?)
70
+ rule_segments += [nil]*(url_segments.size - rule_segments.size) if url_segments.size > rule_segments.size
71
+ pares = {}
72
+ skip_flag = false
73
+ fail_flag = false
74
+ rule_segments.zip(url_segments).each do |rule_segment, url_segment|
75
+ skip_flag = true if rule_segment == '**'
76
+ if rule_segment =~ /^:[a-z]+\w*$/i && url_segment =~ /^[a-z0-9_]+$/
77
+ pares[rule_segment[1..-1].to_sym] = url_segment
78
+ elsif (rule_segment == url_segment) || (rule_segment == '*' && url_segment =~ /^[a-z0-9_]+$/) || (rule_segment == nil && skip_flag) || rule_segment == '**'
79
+ else
80
+ fail_flag = true
81
+ break
82
+ end
83
+ end
84
+ fail_flag = true if rule_trail_slash != url_trail_slash
85
+ return !fail_flag, pares
86
+ elsif rule.is_a? Regexp
87
+ match = rule.match url
88
+ if match
89
+ pares = Hash[match.names.map(&:to_sym).zip(match.captures)]
90
+ return true, pares
91
+ else
92
+ return false, {}
93
+ end
94
+ end
95
+ end
96
+
97
+
98
+ def self.invoke_controller controller
99
+ @controllers ||= {}
100
+ controller = controller.to_s
101
+ require File.join(PROJECT_ROOT, 'app/controllers', controller.to_s)
102
+ @controllers[controller] ||= Kernel.const_get(Alfa::Support.capitalize_name(controller)+'Controller').new
103
+ @controllers[controller]
104
+ end
105
+
106
+ def self.render_template template, data = {}
107
+ t = self.loader.get_template File.join('views', template)
108
+ t.render data
109
+ end
110
+
111
+ def self.render_layout layout, data = {}
112
+ t = self.loader.get_template File.join('layouts', layout)
113
+ t.render data
114
+ end
115
+
116
+ def self.loader
117
+ @loader ||= Ruty::Loaders::Filesystem.new(:dirname => File.join(PROJECT_ROOT, 'app'))
118
+ end
119
+
120
+ end
121
+ end
data/lib/alfa.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ require 'alfa/support'
3
+ require 'alfa/exceptions'
4
+ require 'alfa/web_application'
5
+ require 'alfa/cli_application'
6
+ require 'alfa/controller'
7
+ require 'alfa/database'
8
+ require 'alfa/models'
@@ -0,0 +1,75 @@
1
+ # STYLES
2
+
3
+ class Ruty::Tags::RequireStyle < Ruty::Tag
4
+ @@styles = []
5
+ def initialize parser, argstring
6
+ @@styles << argstring unless @@styles.include? argstring
7
+ end
8
+ def self.clean_cache
9
+ @@styles = []
10
+ end
11
+ Ruty::Tags.register(self, :require_style)
12
+ end
13
+
14
+
15
+ class Ruty::Tags::Styles < Ruty::Tag
16
+ def initialize parser, argstring
17
+ end
18
+ def render_node context, stream
19
+ Ruty::Tags::RequireStyle.class_variable_get(:@@styles).each do |file|
20
+ stream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"#{file}\"/>\n"
21
+ end
22
+ end
23
+ Ruty::Tags.register(self, :styles)
24
+ end
25
+
26
+ # SCRIPTS
27
+
28
+ # Require external script that must be included at bottom of page.
29
+ class Ruty::Tags::RequireScript < Ruty::Tag
30
+ def initialize parser, argstring
31
+ end
32
+ Ruty::Tags.register(self, :require_script)
33
+ end
34
+
35
+ # Inline script placed at bottom after required scripts.
36
+ class Ruty::Tags::Script < Ruty::Tag
37
+ def initialize parser, argstring
38
+ end
39
+ Ruty::Tags.register(self, :script)
40
+ end
41
+
42
+ # Consolidation of required and inline scripts, puts at bottom of page before </body> tag.
43
+ class Ruty::Tags::Scripts < Ruty::Tag
44
+ def initialize parser, argstring
45
+ end
46
+ Ruty::Tags.register(self, :scripts)
47
+ end
48
+
49
+ # Inline script placed at top of page.
50
+ class Ruty::Tags::TopScript < Ruty::Tag
51
+ def initialize parser, argstring
52
+ end
53
+ Ruty::Tags.register(self, :top_script)
54
+ end
55
+
56
+ # Consolidation of inline top scripts, puts at top of page before </head> tag
57
+ class Ruty::Tags::TopScripts < Ruty::Tag
58
+ def initialize parser, argstring
59
+ end
60
+ Ruty::Tags.register(self, :top_scripts)
61
+ end
62
+
63
+ # Shortcut for jquery (required bottom)
64
+ class Ruty::Tags::RequireJquery < Ruty::Tag
65
+ def initialize parser, argstring
66
+ end
67
+ Ruty::Tags.register(self, :require_jquery)
68
+ end
69
+
70
+ # Shortcut for jquery plugin (required bottom)
71
+ class Ruty::Tags::RequireJqueryPlugin < Ruty::Tag
72
+ def initialize parser, argstring
73
+ end
74
+ Ruty::Tags.register(self, :require_jquery_plugin)
75
+ end
data/test/test_alfa.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'test/unit'
2
+ require 'alfa'
3
+
4
+ class DB1 < Alfa::Database::MySQL; end
5
+ class DB2 < Alfa::Database::MySQL; end
6
+
7
+ class AlfaTest < Test::Unit::TestCase
8
+ def test_route_match
9
+ # string rules, positive cases
10
+ assert_equal([true, {}], Alfa::WebApplication.route_match?('/', '/'))
11
+ assert_equal([true, {action: 'foo'}], Alfa::WebApplication.route_match?('/:action', '/foo'))
12
+ assert_equal([true, {action: 'foo'}], Alfa::WebApplication.route_match?('/:action/', '/foo/'))
13
+ assert_equal([true, {controller: 'foo', action: 'bar'}], Alfa::WebApplication.route_match?('/:controller/:action', '/foo/bar'))
14
+ assert_equal([true, {}], Alfa::WebApplication.route_match?('/foo/bar', '/foo/bar'))
15
+ assert_equal([true, {}], Alfa::WebApplication.route_match?('/*/bar', '/foo/bar'))
16
+ assert_equal([true, {action: 'bar'}], Alfa::WebApplication.route_match?('/*/:action', '/foo/bar'))
17
+ assert_equal([true, {}], Alfa::WebApplication.route_match?('/**', '/foo/bar'))
18
+ assert_equal([true, {controller: 'foo'}], Alfa::WebApplication.route_match?('/:controller/**', '/foo/bar/baz'))
19
+
20
+ # string rules, negative cases
21
+ assert_equal([false, {action: 'foo'}], Alfa::WebApplication.route_match?('/:action', '/foo/'))
22
+ assert_equal([false, {action: 'foo'}], Alfa::WebApplication.route_match?('/:action/', '/foo'))
23
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/foo/bar/', '/foo/bar'))
24
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/*', '/foo/bar'))
25
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/*/', '/foo/bar'))
26
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/*', '/foo/bar/'))
27
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/**/', '/foo/bar'))
28
+ assert_equal([false, {}], Alfa::WebApplication.route_match?('/**', '/foo/bar/'))
29
+
30
+ # regexp rules, positive cases
31
+ rule = Regexp.new('^/(?<controller>[^/]+)/(?<action>[^/]+)?$')
32
+ assert_equal([true, {controller: 'default', action: 'index'}], Alfa::WebApplication.route_match?(rule, '/default/index'))
33
+
34
+ # regexp rules, negative cases
35
+ rule = Regexp.new('^/(?<controller>[^/]+)/(?<action>[^/]+)?$')
36
+ assert_equal([false, {}], Alfa::WebApplication.route_match?(rule, '/'))
37
+ end
38
+
39
+
40
+ def test_capitalize_name
41
+ assert_equal('Foo', Alfa::Support.capitalize_name(:foo))
42
+ assert_equal('Foo', Alfa::Support.capitalize_name('foo'))
43
+ assert_equal('Foo', Alfa::Support.capitalize_name('FOO'))
44
+ assert_equal('Foo', Alfa::Support.capitalize_name('Foo'))
45
+ assert_equal('FooBar', Alfa::Support.capitalize_name(:foo_bar))
46
+ assert_equal('FooBar', Alfa::Support.capitalize_name('foo_bar'))
47
+ assert_equal('FooBar', Alfa::Support.capitalize_name(:foo__bar))
48
+ assert_equal('BarBaz', Alfa::Support.capitalize_name('foo/bar_baz'))
49
+ end
50
+
51
+ def test_inheritance
52
+ DB1.host = 'localhost'
53
+ DB2.host = 'otherhost'
54
+ assert_equal('localhost', DB1.host)
55
+ assert_equal('otherhost', DB2.host)
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alfa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Valentin Syrovatskiy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rvm
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rack
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: ruty
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: mysql2
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rvm
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rake
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rack
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: ruty
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: mysql2
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: ''
175
+ email: vsyrovat@gmail.com
176
+ executables: []
177
+ extensions: []
178
+ extra_rdoc_files: []
179
+ files:
180
+ - lib/alfa/cli_application.rb
181
+ - lib/alfa/exceptions.rb
182
+ - lib/alfa/support.rb
183
+ - lib/alfa/web_application.rb
184
+ - lib/alfa/controller.rb
185
+ - lib/alfa/models/dummy.rb
186
+ - lib/alfa/models/base.rb
187
+ - lib/alfa/models/base_sql.rb
188
+ - lib/alfa/models/mysql.rb
189
+ - lib/alfa/database/mysql.rb
190
+ - lib/alfa/database.rb
191
+ - lib/alfa/models.rb
192
+ - lib/ruty/tags/resources.rb
193
+ - lib/alfa.rb
194
+ - test/test_alfa.rb
195
+ homepage: http://alfa.7side.ru
196
+ licenses: []
197
+ post_install_message:
198
+ rdoc_options: []
199
+ require_paths:
200
+ - lib
201
+ required_ruby_version: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ! '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
+ none: false
209
+ requirements:
210
+ - - ! '>'
211
+ - !ruby/object:Gem::Version
212
+ version: 1.3.1
213
+ requirements: []
214
+ rubyforge_project:
215
+ rubygems_version: 1.8.23
216
+ signing_key:
217
+ specification_version: 3
218
+ summary: Alfa CMF
219
+ test_files: []