component-framework 0.1.0
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 +7 -0
- data/LICENSE.txt +19 -0
- data/README.md +90 -0
- data/lib/component/framework/directive_processor.rb +31 -0
- data/lib/component/framework/railtie.rb +16 -0
- data/lib/component/framework/sass_importer.rb +41 -0
- data/lib/component/framework/version.rb +5 -0
- data/lib/component/framework.rb +172 -0
- data/lib/component/settings.rb +54 -0
- metadata +94 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 663c497bb487c2f193700b547df7074d6f588200
|
4
|
+
data.tar.gz: 2d757bfa0dc65ffa3f1a7c1ce3f9a724441468b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5454e668f8b6ea498f36e2fcee2521078fa1c7713a6bc63263d04ecf588ca8a0ea4bd83b1dd88b83a6320c36bef67bc3f42f4d8ca55b895e481233df087da18e
|
7
|
+
data.tar.gz: 40f402f768e8efbfc4f8256c306afbfb5626f276051dac23df3667176a3923fab1944afb5b146dec0e9d4dbe3db0e1aafd7db276a4f63415640694b48541f6f7
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Component::Framework
|
2
|
+
|
3
|
+
The minimalistic framework for developing Rails component based applications.
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'component-framework'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install component-framework
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
|
26
|
+
Add the following lines to application.rb after your application class declaration.
|
27
|
+
|
28
|
+
_application.rb_
|
29
|
+
```ruby
|
30
|
+
module My
|
31
|
+
class Application < Rails::Application
|
32
|
+
...
|
33
|
+
end
|
34
|
+
|
35
|
+
Component::Framework.initialize(YourApplication)
|
36
|
+
```
|
37
|
+
|
38
|
+
### Conventions
|
39
|
+
|
40
|
+
|
41
|
+
### Assets
|
42
|
+
|
43
|
+
|
44
|
+
### Folder Structure
|
45
|
+
|
46
|
+
/components/
|
47
|
+
<name>/
|
48
|
+
assets/
|
49
|
+
images/
|
50
|
+
javascripts/
|
51
|
+
stylesheets/
|
52
|
+
api/
|
53
|
+
|
54
|
+
|
55
|
+
### Components Initialization
|
56
|
+
|
57
|
+
|
58
|
+
### Routing
|
59
|
+
|
60
|
+
|
61
|
+
### DB Migrations
|
62
|
+
|
63
|
+
|
64
|
+
### Gemfile
|
65
|
+
|
66
|
+
It's recommended to use `group :component_name` for gems required by particular component.
|
67
|
+
|
68
|
+
|
69
|
+
### Settings
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
settings = Component::Settings.load_settings(:settings)
|
73
|
+
config.settings = settings
|
74
|
+
```
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
## Development
|
79
|
+
|
80
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
81
|
+
|
82
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
83
|
+
|
84
|
+
## Contributing
|
85
|
+
|
86
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/component-framework. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
87
|
+
|
88
|
+
## License
|
89
|
+
|
90
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
class Component::Framework::DirectiveProcessor < Sprockets::DirectiveProcessor
|
3
|
+
|
4
|
+
# `require_components` requires all the components manifest files in project.
|
5
|
+
#
|
6
|
+
# //= require_components assets/javascripts/app.js
|
7
|
+
# will be resolved to {COMPONENT_BASE_DIR}/{COMPONENT_NAME}/assets/javascripts/app.js
|
8
|
+
|
9
|
+
def process_require_components_directive(manifest_subpath = "assets/javascripts/app.js")
|
10
|
+
|
11
|
+
# gather component manifests with absolute paths.
|
12
|
+
manifests_paths = Component::Framework.get_component_names
|
13
|
+
.map {|name| Component::Framework.components_base_dir.join(name, manifest_subpath).to_s}
|
14
|
+
.select { |path| File.exist?(path) }
|
15
|
+
.sort # add predictability to require order
|
16
|
+
|
17
|
+
manifests_paths.each { |path| @required << _resolve_absolute(path, accept: @content_type, pipeline: :self) }
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
|
24
|
+
def _resolve_absolute(path, options = {})
|
25
|
+
# adapted from Sprockets::DirectiveProcessor.resolve
|
26
|
+
uri, deps = @environment.resolve!(path, options.merge(base_path: @dirname))
|
27
|
+
@dependencies.merge(deps)
|
28
|
+
uri
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
# Monkeypatch Rails::Application to remove components tests from application's eager load.
|
3
|
+
class Rails::Application
|
4
|
+
|
5
|
+
# method adopted from Rails::Engine.eager_load!
|
6
|
+
def eager_load!
|
7
|
+
config.eager_load_paths.each do |load_path|
|
8
|
+
matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/
|
9
|
+
Dir.glob("#{load_path}/**/*.rb")
|
10
|
+
.reject { |p| p.include?("/test/") }
|
11
|
+
.sort.each do |file|
|
12
|
+
require_dependency file.sub(matcher, '\1')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Component::Framework
|
2
|
+
|
3
|
+
class ScssTemplate < SassC::Rails::ScssTemplate
|
4
|
+
|
5
|
+
def config_options
|
6
|
+
options = super
|
7
|
+
options[:importer] = Component::Framework::SassImporter
|
8
|
+
return options
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
class SassImporter < SassC::Rails::Importer
|
15
|
+
|
16
|
+
def imports(path, parent_path)
|
17
|
+
return _import_components if path == "{all-components}"
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
|
25
|
+
def _import_components
|
26
|
+
context = options[:sprockets][:context]
|
27
|
+
_component_manifest_files.map do |filename|
|
28
|
+
context.depend_on(filename)
|
29
|
+
SassC::Importer::Import.new(filename)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def _component_manifest_files
|
35
|
+
Component::Framework.get_component_names
|
36
|
+
.map{ |component| Component::Framework.components_base_dir.join(component, "assets/stylesheets/app.scss").to_s }
|
37
|
+
.select { |path| File.exists?(path) }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require "component/framework/version"
|
2
|
+
require "component/settings"
|
3
|
+
|
4
|
+
module Component
|
5
|
+
module Framework
|
6
|
+
|
7
|
+
COMPONENT_IMAGE_ASSETS = lambda do |logical_path, filename|
|
8
|
+
filename.start_with?(components_base_dir.to_s) &&
|
9
|
+
%w(.png .jpg .jpeg .gif).include?(File.extname(logical_path))
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def self.components_base_dir
|
14
|
+
@base_dir ||= Rails.root.join("components")
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def self.initialize(application, assets_pipeline: true)
|
19
|
+
|
20
|
+
# patch Rails
|
21
|
+
require "component/framework/railtie"
|
22
|
+
|
23
|
+
log("Components Initialization Started")
|
24
|
+
log("Components Path: #{components_base_dir}")
|
25
|
+
|
26
|
+
# add eager and autoload path that will allow to eager load and resolve components with namespaces.
|
27
|
+
application.config.paths.add components_base_dir.to_s, eager_load: true
|
28
|
+
|
29
|
+
log("Discovered Components: #{get_component_names.join(", ")}")
|
30
|
+
|
31
|
+
log("Register DB Migrations")
|
32
|
+
_get_component_migrations_paths.each { |path| application.config.paths["db/migrate"].push(path) }
|
33
|
+
|
34
|
+
log("Register Components Routes")
|
35
|
+
application.config.paths["config/routes.rb"].unshift(*_get_component_routing_paths)
|
36
|
+
|
37
|
+
log("Register Components Helpers")
|
38
|
+
application.config.paths["app/helpers"].unshift(*_get_component_helpers_paths)
|
39
|
+
|
40
|
+
if assets_pipeline
|
41
|
+
_initialize_assets_pipeline(application)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Initialize components after all initialization finished.
|
45
|
+
application.config.after_initialize do |app|
|
46
|
+
|
47
|
+
log("Load Components Initializers")
|
48
|
+
_load_components_initializers
|
49
|
+
|
50
|
+
components = get_component_modules
|
51
|
+
log("Initialize Components")
|
52
|
+
components.each {|component| component.send("init") if component.respond_to?("init") }
|
53
|
+
|
54
|
+
log("Post-Initialize Components")
|
55
|
+
components.each {|component| component.send("ready") if component.respond_to?("ready") }
|
56
|
+
|
57
|
+
log("Components Initialization Done")
|
58
|
+
end
|
59
|
+
|
60
|
+
log("Configuration Finished")
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def self.get_component_names
|
65
|
+
Dir.entries(components_base_dir)
|
66
|
+
.select { |entry| (entry !="." && entry != "..") and File.directory? components_base_dir.join(entry) }
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def self.get_component_modules
|
71
|
+
get_component_names.map { |name| component_module_by_name(name) }
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def self.component_module_by_name(name)
|
76
|
+
return name.camelize.constantize
|
77
|
+
rescue NameError, ArgumentError
|
78
|
+
message = "Component #{name} not found"
|
79
|
+
log(message)
|
80
|
+
raise ComponentNotFoundError, message
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
|
87
|
+
def self._initialize_assets_pipeline(application)
|
88
|
+
|
89
|
+
log("Register Components Assets")
|
90
|
+
application.config.assets.paths += _get_component_assets_paths
|
91
|
+
application.config.assets.precompile += [COMPONENT_IMAGE_ASSETS]
|
92
|
+
|
93
|
+
|
94
|
+
# We need to override SassC configuration
|
95
|
+
# so we need to register after SassC app.config.assets.configure
|
96
|
+
application.initializer :setup_component_sass, group: :all, after: :setup_sass do |app|
|
97
|
+
|
98
|
+
require "component/framework/directive_processor"
|
99
|
+
require "component/framework/sass_importer"
|
100
|
+
|
101
|
+
app.config.assets.configure do |sprockets_env|
|
102
|
+
Component::Framework.log("Register assets directive processors")
|
103
|
+
sprockets_env.unregister_preprocessor "application/javascript", Sprockets::DirectiveProcessor
|
104
|
+
sprockets_env.unregister_preprocessor "text/css", Sprockets::DirectiveProcessor
|
105
|
+
|
106
|
+
sprockets_env.register_preprocessor "application/javascript", Component::Framework::DirectiveProcessor
|
107
|
+
sprockets_env.register_preprocessor "text/css", Component::Framework::DirectiveProcessor
|
108
|
+
|
109
|
+
Component::Framework.log("Add .scss `@import all-components` support")
|
110
|
+
sprockets_env.register_transformer "text/scss", "text/css", Component::Framework::ScssTemplate.new
|
111
|
+
sprockets_env.register_engine(".scss", Component::Framework::ScssTemplate, { silence_deprecation: true })
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def self._get_component_migrations_paths
|
118
|
+
_existing_component_subpaths("migrations")
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def self._get_component_helpers_paths
|
123
|
+
_existing_component_subpaths("api/helpers")
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def self._get_component_assets_paths
|
128
|
+
styles = _existing_component_subpaths("assets/stylesheets")
|
129
|
+
scripts = _existing_component_subpaths("assets/javascripts")
|
130
|
+
images = _existing_component_subpaths("assets/images")
|
131
|
+
return styles + scripts + images
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def self._get_component_routing_paths
|
136
|
+
# All routes.rb files under /components folder
|
137
|
+
Dir.glob(components_base_dir.join("**/routes.rb"))
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
def self._load_components_initializers
|
142
|
+
# initializers are optional, so ignore the missing ones
|
143
|
+
get_component_names.each do |name|
|
144
|
+
begin
|
145
|
+
require_relative(components_base_dir.join("#{name}/initialize"))
|
146
|
+
rescue LoadError
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def self._existing_component_subpaths(subpath)
|
153
|
+
get_component_names.map { |component| components_base_dir.join(component, subpath).to_s }
|
154
|
+
.select { |path| File.exists?(path) }
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def self.log(message)
|
159
|
+
message = "[CF init] " + message
|
160
|
+
if Rails.logger
|
161
|
+
Rails.logger.info(message)
|
162
|
+
else
|
163
|
+
puts message
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
class ComponentNotFoundError < StandardError; end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
INCLUDE_KEY = "__include__"
|
3
|
+
|
4
|
+
|
5
|
+
module Component
|
6
|
+
|
7
|
+
module Settings
|
8
|
+
|
9
|
+
# Loads settings YAML and returns hash with settings names/values
|
10
|
+
#
|
11
|
+
# In case {name}.override.yml file present, its content merged on top of settings file.
|
12
|
+
#
|
13
|
+
# Adapted from Rails.application.config_for()
|
14
|
+
# YAML format key:env:value
|
15
|
+
#
|
16
|
+
# @param name [String] settings file name.
|
17
|
+
# @param env [String] environment name, by default Rails.env will be used.
|
18
|
+
def self.load_settings(name, env: nil)
|
19
|
+
env ||= Rails.env
|
20
|
+
settings = _load_settings_file(name, env)
|
21
|
+
if settings.nil?
|
22
|
+
raise "Could not load configuration. No such file - #{name}.yml"
|
23
|
+
end
|
24
|
+
|
25
|
+
overrides = _load_settings_file(name.to_s + ".override", env)
|
26
|
+
if overrides.present?
|
27
|
+
settings.deep_merge!(overrides)
|
28
|
+
end
|
29
|
+
|
30
|
+
settings.with_indifferent_access.freeze
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self._load_settings_file(name, env)
|
35
|
+
yaml_file = Pathname.new("#{Rails.application.paths["config"].existent.first}/#{name}.yml")
|
36
|
+
|
37
|
+
if yaml_file.exist?
|
38
|
+
require "erb"
|
39
|
+
yaml = (YAML.load(ERB.new(yaml_file.read).result) || {})
|
40
|
+
|
41
|
+
result = yaml.map { |k, v| [k, v[env] || {}] }.to_h
|
42
|
+
|
43
|
+
return result
|
44
|
+
else
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
rescue Psych::SyntaxError => e
|
48
|
+
raise "YAML syntax error occurred while parsing #{yaml_file}. " \
|
49
|
+
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
50
|
+
"Error: #{e.message}"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: component-framework
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Yegorov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-05 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.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: railties
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- ayroff@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- LICENSE.txt
|
63
|
+
- README.md
|
64
|
+
- lib/component/framework.rb
|
65
|
+
- lib/component/framework/directive_processor.rb
|
66
|
+
- lib/component/framework/railtie.rb
|
67
|
+
- lib/component/framework/sass_importer.rb
|
68
|
+
- lib/component/framework/version.rb
|
69
|
+
- lib/component/settings.rb
|
70
|
+
homepage: https://github.com/brokermint/component-framework
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.6.13
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: The minimalistic framework for developing component based applications.
|
94
|
+
test_files: []
|