airslie-engineer 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3845ee121169c0e4368a5f9b718ea104d35e1089891867f044514641b21746ba
4
+ data.tar.gz: a7cf566c986b3ba47595144d12748738d386ab8d93bd20ad87c1195fa3cf5337
5
+ SHA512:
6
+ metadata.gz: 580a40b11805629f416007b1045d18314fc1b26c3707558c87d551531a200345148bc823e55dfb093f48668e2f83877084d909f31e99d3c74ad81879fec91a9f
7
+ data.tar.gz: 2736a5837435728a4267619d86c545147be3269dec5a8d24469103f205931d0198483b70bccf64e676e586facf8bfc08da9eb18ec12874aa482a8405cd715813
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Airslie Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ [![Maintainability](https://api.codeclimate.com/v1/badges/112e9f4a7cda28bd73d7/maintainability)](https://codeclimate.com/github/airslie/engineer/maintainability)
2
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/112e9f4a7cda28bd73d7/test_coverage)](https://codeclimate.com/github/airslie/engineer/test_coverage)
3
+
4
+ # Engineer
5
+
6
+ This gem makes developing a Renalware plugin (a Rails engine) a little easier.
7
+ It does most of the standard Engine initialization including:
8
+
9
+ - appending the engine's `db/migrate`, `db/triggers`, `db/functions` and `db/views` paths to the
10
+ application's `config.paths` so that migrations across all engines and the app itself - and any
11
+ sql definition files referenced in migrations - can be found during a `db:migrate`
12
+ - loading any `config/locale/**/*.yml` that exist in the engine.
13
+ - more to follow..
14
+
15
+ ## Usage
16
+
17
+ In your Rails engine add the following to `lib/xxxx/engine.rb`:
18
+
19
+ ```ruby
20
+ class Engine < ::Rails::Engine
21
+ isolate_namespace Renalware::Xxxx
22
+ include Engineer::DefaultInitializers
23
+ ...
24
+ end
25
+ ```
26
+
27
+ ## Installation
28
+ Add this line to your application's Gemfile:
29
+
30
+ ```ruby
31
+ gem 'engineer'
32
+ ```
33
+
34
+ And then execute:
35
+ ```bash
36
+ $ bundle
37
+ ```
38
+
39
+ # Development Tasks
40
+
41
+ - [ ] Add tests
42
+ - [ ] Add a generator to bring in standard files for a new Renalware plugin
43
+ - [ ] Look for other Engine boiler-plate code we can move here.
44
+
45
+ ## License
46
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ require "rdoc/task"
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = "rdoc"
13
+ rdoc.title = "Engineer"
14
+ rdoc.options << "--line-numbers"
15
+ rdoc.rdoc_files.include("README.md")
16
+ rdoc.rdoc_files.include("lib/**/*.rb")
17
+ end
18
+
19
+ require "bundler/gem_tasks"
20
+
21
+ require "rake/testtask"
22
+
23
+ Rake::TestTask.new(:test) do |t|
24
+ t.libs << "test"
25
+ t.pattern = "test/**/*_test.rb"
26
+ t.verbose = false
27
+ end
28
+
29
+ task default: :test
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "engineer/railtie"
4
+ require "engineer/database/scenic"
5
+ require "engineer/database/initializers"
6
+ require "engineer/locale/initializers"
7
+ require "engineer/default_initializers"
8
+ require "engineer/seed_extensions"
9
+
10
+ module Engineer
11
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ module Database
5
+ #
6
+ # Add db/migrate, db/views, db/triggers and db/functions folders to app.config.paths so they
7
+ # can be resolved during migration
8
+ # Be sure sure to append to any existing entries in #paths, because other engines, and
9
+ # the app itself, will add their paths too.
10
+ # This step is especially important for the Scenic gem; sql view definitions in db/views
11
+ # are referenced by filename from migrations, and we need to be able to locate those files.
12
+ # The Scenic issue is a bit more too it see scenic.rb for more info.
13
+ # Note that a common but way more kludgy approach to this problem is to copy the migrations
14
+ # views etc from each gen into the host app with a rake task. This is a slicker a less
15
+ # error-proone solution.
16
+ #
17
+ class AppendEnginePaths
18
+ attr_reader :app, :engine_config
19
+
20
+ def initialize(app:, engine_config:)
21
+ @app = app
22
+ @engine_config = engine_config
23
+ end
24
+
25
+ def call
26
+ append_migration_paths
27
+ append_other_paths
28
+ end
29
+
30
+ # db/migrate paths are handled rather differently.
31
+ # Prevent duplicate migrations if we are db:migrating at the engine level (eg when
32
+ # running tests) rather than the host app.
33
+ def append_migration_paths
34
+ if running_in_dummy_app? || running_outside_of_engine?
35
+ add_engine_db_path_to_app("migrate")
36
+ end
37
+ end
38
+
39
+ def append_other_paths
40
+ %w(views functions triggers).each do |sub_folder|
41
+ add_engine_db_path_to_app(sub_folder)
42
+ end
43
+ end
44
+
45
+ def add_engine_db_path_to_app(sub_folder)
46
+ key = "db/#{sub_folder}"
47
+ path_to_db_things_in_engine = Rails.root.join(engine_config.root, "db", sub_folder)
48
+ app_config = app.config
49
+ app_config.paths[key] ||= []
50
+ app_config.paths[key] << path_to_db_things_in_engine
51
+ end
52
+
53
+ def running_in_dummy_app?
54
+ Dir.pwd.ends_with?("dummy")
55
+ end
56
+
57
+ def running_outside_of_engine?
58
+ app.root.to_s.match(engine_config.root.to_s + File::SEPARATOR).nil?
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./append_engine_paths"
4
+
5
+ module Engineer
6
+ module Database
7
+ class Initializers
8
+ attr_reader :klass
9
+
10
+ def initialize(klass)
11
+ @klass = klass
12
+ end
13
+
14
+ def add
15
+ klass.initializer :"append_migrations_in_#{klass.name.underscore.tr("/", "_")}" do |app|
16
+ AppendEnginePaths.new(app: app, engine_config: config).call
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ module Database
5
+ # The scenic gem supports loading SQL view definition files from a db/views folder but only
6
+ # supports one folder (it looks in app.config.paths["db/views"] and takes the last one) which
7
+ # works fine if you are using a rake task to copy all your views from various engines into the
8
+ # host app. But this a bit issues prone and it is much nicer to add each engine's db/views
9
+ # folder to app.config.paths (we do this in the Engineer::Database::Initializers class provided
10
+ # the engine includes the appropriate file) and then here we override the Scenic
11
+ # Definition#to_sql method and when a view definition file is requested, search all db/views
12
+ # paths - which may search in several engines and host app itself - and hopefully find the file
13
+ # we are looking for. In theory that file should be in the same engine/app that its
14
+ # corresponding migration is in... though we can't verify that and its unlikely
15
+ # We raise an error if we find two matching files i.e. a view definition file of the same name
16
+ # in two gems.
17
+ module ResolveScenicViewsAnywhere
18
+ def to_sql
19
+ view_definition_file = find_view_definition_among_all_possible_paths
20
+
21
+ File.read(view_definition_file).tap do |content|
22
+ if content.empty?
23
+ raise "Define view query in #{path} before migrating."
24
+ end
25
+ end
26
+ end
27
+
28
+ def find_view_definition_among_all_possible_paths
29
+ found_files = all_full_paths.select{ |path| File.exist?(path) }
30
+ if found_files.length > 1
31
+ raise "More than one view definition matches the name #{filename}\n #{found_files}"
32
+ end
33
+
34
+ found_files.first
35
+ end
36
+
37
+ def all_full_paths
38
+ app = Rails.application
39
+ return super unless defined?(app) && app.present?
40
+
41
+ app.config.paths["db/views"].map { |path| File.join(path, filename) }
42
+ end
43
+ end
44
+
45
+ if defined?(Scenic)
46
+ Scenic::Definition.send(:prepend, ResolveScenicViewsAnywhere)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module Engineer
6
+ module Database
7
+ module SeedHelper
8
+ def log(msg, type: :full)
9
+ case type
10
+ when :full
11
+ print "-----> #{msg}"
12
+ if block_given?
13
+ ms = Benchmark.ms { yield }
14
+ milliseconds = "#{ms.to_i}ms"
15
+ print "\r-----> #{milliseconds.ljust(8, ' ')} #{msg}"
16
+ end
17
+ print "\n"
18
+ when :sub
19
+ puts " #{msg}"
20
+ else
21
+ raise "Unknown type #{type}"
22
+ end
23
+ end
24
+
25
+ def log_section(title)
26
+ log "-" * 80
27
+ log title
28
+ log "-" * 80
29
+ end
30
+
31
+ def without_papertrail_versioning_for(klass)
32
+ raise ArgumentError unless klass.is_a? Class
33
+ klass.paper_trail.disable
34
+ yield
35
+ klass.paper_trail.enable
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ module DefaultInitializers
5
+ def self.included(klass)
6
+ Database::Initializers.new(klass).add
7
+ Locale::Initializers.new(klass).add
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Add an initializer to pull in the Engine's locale yml files.
5
+ #
6
+ module Engineer
7
+ module Locale
8
+ class Initializers
9
+ def initialize(klass)
10
+ @klass = klass
11
+ end
12
+
13
+ def add
14
+ klass.initializer :"add_locals_in_#{klass.name.underscore.tr("/", "_")}" do |app|
15
+ # Because we have a different binding here we can't call private Initializers
16
+ # members so instead explicitly call a class method on ourselves passing in the
17
+ # variables we need.
18
+ Engineer::Locale::Initializers.add_engine_locale_files(app, config)
19
+ end
20
+ end
21
+
22
+ def self.add_engine_locale_files(app, engine_config)
23
+ engine_locale_files = Dir[engine_config.root.join("config", "locales", "**", "*.{rb,yml}")]
24
+ i18n = app.config.i18n
25
+ i18n.load_path += engine_locale_files
26
+ i18n.default_locale = "en-GB"
27
+ i18n.fallbacks = [:en]
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :klass
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ class Railtie < ::Rails::Railtie
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ module SeedExtensions
5
+ def load_demo_seed
6
+ require root.join("demo_data/seeds")
7
+ end
8
+ end
9
+ end
10
+
11
+ Rails::Engine.prepend(Engineer::SeedExtensions)
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Engineer
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # desc "Explaining what the task does"
4
+ # task :engineer do
5
+ # # Task goes here
6
+ # end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: airslie-engineer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Airslie Ltd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.2
27
+ description: Making Renalware plugin development easier
28
+ email:
29
+ - dev@airslie.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - lib/engineer.rb
38
+ - lib/engineer/database/append_engine_paths.rb
39
+ - lib/engineer/database/initializers.rb
40
+ - lib/engineer/database/scenic.rb
41
+ - lib/engineer/database/seed_helper.rb
42
+ - lib/engineer/default_initializers.rb
43
+ - lib/engineer/locale/initializers.rb
44
+ - lib/engineer/railtie.rb
45
+ - lib/engineer/seed_extensions.rb
46
+ - lib/engineer/version.rb
47
+ - lib/tasks/engineer_tasks.rake
48
+ homepage: https://github.com/airslie/engineer
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.7.6
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Making Renalware plugin development easier
72
+ test_files: []