rails2lb4 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 17a1f0ccbd6c81c97d997cba4184988c8a6932b50091bd6ce5d4123621159258
4
+ data.tar.gz: 23f60cfdffac43b3fa4e23e63db2096e4b3761556521c861c5a82ef863a37776
5
+ SHA512:
6
+ metadata.gz: 803ccfbdb19c79a9f07dc07975fb215bbaaa3044b7c682f9efdc126e4ef3d1a95653a9a9b8cf58165f5f4f4185a619f8ec7ce9941c51fa533359f3778b8b11f6
7
+ data.tar.gz: 26175cd91f0588e6728a0af73284e46f4157250b5d26ec24a080d8e7814e91b7e0f8056d13d1fbc2df922beb7174a7db62067c3ca5003a509c446b05f101fe50
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ MIT license
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.
@@ -0,0 +1,68 @@
1
+ **Warning**: this application is only demo quality at the moment. Do not use on
2
+ an existing loopback4 appication is not under version control where all of the
3
+ changes have already been committed as this application may overwrite files.
4
+
5
+ This tool will create a loopback4 model, respository, and datasource based on
6
+ an existing Rails application.
7
+
8
+ Step 0
9
+ ------
10
+
11
+ Install `rails` and/or `loopback4` if they are not already installed:
12
+
13
+ gem install rails
14
+ npm install -g loopback-cli
15
+
16
+ Note: in order to install these tools, you need to have previously installed `ruby`, `node`, `npm` and other tools. Check the installation instructions for
17
+ [rails](https://guides.rubyonrails.org/getting_started.html#installing-rails) and
18
+ [loopback4](https://loopback.io/doc/en/lb4/Getting-started.html) for details.
19
+
20
+ Step 1
21
+ ------
22
+
23
+ Install this tool:
24
+
25
+ gem install rails2lb4
26
+
27
+ Step 2
28
+ ------
29
+
30
+ Locate a Rails application. If you don't already have one, you can follow the [Creating the Blog Application](https://guides.rubyonrails.org/getting_started.html#creating-the-blog-application) in the Rails guide, or
31
+ clone it from [https://github.com/rubys/railsguide_blog](https://github.com/rubys/railsguide_blog.git).
32
+
33
+ Step 3
34
+ ------
35
+
36
+ Locate or create a new loopback application. To create a new application:
37
+
38
+ lb4 app blog
39
+
40
+ Step 4
41
+ ------
42
+
43
+ Run the tool, specifying the path to the source rails and destination loopback applications:
44
+
45
+ rails2lb4 /path/to/rails/blog /path/to/loopback4/blog
46
+
47
+ Note: by default, this tool will set up the loopback application to access the Rails `development` database. If you would like to access another database, set the `RAILS_ENV` environment variable before running this step.
48
+
49
+
50
+ Step 5 (optional)
51
+ -----------------
52
+
53
+ Create REST controllers for the new models:
54
+
55
+ lb4 controller article
56
+ lb4 controller comment
57
+
58
+ Note: specify `number` as the type of `id` for these controllers.
59
+
60
+ Step 6 (optional)
61
+ -----------------
62
+
63
+ Start the loopback4 server:
64
+
65
+ npm start
66
+
67
+ Note: by default, both Rails and Loopback4 default to listen to port 3000. Be sure to stop your Rails server before starting your loopback4 server.
68
+
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ source = target = Dir.pwd
4
+
5
+ if ARGV.length == 2
6
+ source, target = ARGV
7
+ elsif ARGV.length == 1
8
+ if File.exist? File.expand_path('Rakefile', ARGV.first)
9
+ source = File.expand_path(ARGV.first)
10
+ elsif File.exist? File.expand_path('index.ts', ARGV.first)
11
+ target = File.expand_path(ARGV.first)
12
+ end
13
+ else
14
+ STDERR.puts "Usage: #{$0} [source] [target]"
15
+ exit 1
16
+ end
17
+
18
+ unless File.exist? File.expand_path('Rakefile', source)
19
+ STDERR.puts 'source directory is not a Rails app'
20
+ exit 1
21
+ end
22
+
23
+ unless File.exist? File.expand_path('index.ts', target)
24
+ STDERR.puts 'target directory is not a lb4 app'
25
+ exit 1
26
+ end
27
+
28
+ require 'rails2lb4'
29
+
30
+ rails2lb4 source, target
@@ -0,0 +1,137 @@
1
+ require 'erubis'
2
+ require 'ansi'
3
+ require 'yaml'
4
+ require 'json'
5
+
6
+ require 'active_support/core_ext/string'
7
+ require 'active_support/inflector'
8
+
9
+ def rails2lb4(source, target)
10
+ # import custom pluralization
11
+ if File.exist? "#{source}/config/initializers/inflections.rb"
12
+ require "#{source}/config/initializers/inflections.rb"
13
+ end
14
+
15
+ # define a write operation that colorizes output and determines if the
16
+ # output represent new content or a change.
17
+ def target.write path, contents
18
+ dest = File.join(self, path)
19
+ if File.size?(dest) and IO.read(dest) == contents
20
+ puts ANSI.blue { 'skipping ' } + path
21
+ else
22
+ if File.size?(dest)
23
+ puts ANSI.bold { ANSI.magenta { 'updating ' } } + path
24
+ else
25
+ puts ANSI.bold { ANSI.green { 'creating ' } } + path
26
+ end
27
+ IO.write dest, contents
28
+ end
29
+ end
30
+
31
+ # determine the database type from the configuration
32
+ environment = ENV['RAILS_ENV'] || 'development'
33
+ database = YAML.load_file("#{source}/config/database.yml")
34
+ @adapter = database[environment]['adapter']
35
+
36
+ # common configuration
37
+ config = {
38
+ name: @adapter,
39
+ connector: "loopback-connector-#{@adapter}"
40
+ }
41
+
42
+ # database specific configuration
43
+ if @adapter == 'sqlite3'
44
+ config[:file] = File.expand_path(database[environment]['database'], source)
45
+
46
+ Dir.chdir target do
47
+ unless IO.read('package.json').include? 'loopback-connector-sqlite3'
48
+ system 'npm install loopback-connector-sqlite3 --save'
49
+ end
50
+ end
51
+
52
+ elsif @adapter == 'mysql' or @adapter == 'postgresql'
53
+ environment = database[environment]
54
+ %w(database host password.port username).each do |property|
55
+ config[property] = environment[property] if environment[property]
56
+ end
57
+
58
+ if @adapter == 'mysql'
59
+ config[:socketPath] = environtment[:socket] if environment[:socket]
60
+ config[:connectionLimit] = environtment[:pool] if environment[:pool]
61
+ end
62
+ end
63
+
64
+ # produce datasource.ts
65
+ template = File.read(File.join(__dir__, '../templates/datasource.erb'))
66
+ datasource = Erubis::Eruby.new(template).result(binding)
67
+ path = File.join('src', 'datasources', "#{@adapter}.datasource.ts")
68
+ target.write path, datasource
69
+
70
+ # produce datasource.json
71
+ path = File.join('src', 'datasources', "#{@adapter}.datasource.json")
72
+ target.write path, JSON.pretty_generate(config)
73
+
74
+ # produce datasource/index.ts
75
+ index = Dir["#{target}/src/datasources/*.datasource.ts"].sort.
76
+ map {|file| "export * from './#{File.basename(file, '.ts')}';"}.
77
+ join("\n") + "\n"
78
+ target.write 'src/datasources/index.ts', index
79
+
80
+ # parse schema.rb from the source
81
+ schema = IO.read("#{source}/db/schema.rb")
82
+ table = /^\s+create_table "([^"]+)",.*?\n(.*?)\n\s+end/m
83
+
84
+ data_types = {
85
+ "integer" => "number",
86
+ "float" => "number",
87
+ "text" => "string",
88
+ "boolean" => "boolean",
89
+ "date" => "Date",
90
+ "datetime" => "Date",
91
+ }
92
+
93
+ tables = {}
94
+ schema.scan(table).each do |name, ddl|
95
+ cols = ddl.scan(/^\s+t\.(\w+)\s+"(\w+)/).
96
+ map {|names| [names.last, data_types[names.first] || names.first]}.to_h
97
+ tables[name] = cols
98
+ end
99
+
100
+ # produce model.ts and repository.ts for each model
101
+ Dir["#{source}/app/models/*.rb"].sort.each do |file|
102
+ model = File.read(file)
103
+ basename = File.basename(file, '.rb')
104
+ @table = tables[basename.pluralize] || {}
105
+ @class_name = model[/class (\w+)/, 1]
106
+ @table_name = @class_name.downcase.pluralize
107
+
108
+ @belongs_to = model.scan(/^\s+belongs_to\s*:(\w+)/).
109
+ map {|(name)| [name, name.camelcase]}.to_h
110
+ @has_many = model.scan(/^\s+has_many\s*:(\w+)/).
111
+ map {|(name)| [name.singularize, name.singularize.camelcase]}.to_h
112
+
113
+ template = File.read(File.join(__dir__, '../templates/model.erb'))
114
+ model = Erubis::Eruby.new(template).result(binding)
115
+
116
+ path = File.join('src', 'models', basename+'.model.ts')
117
+ target.write path, model
118
+
119
+ template = File.read(File.join(__dir__, '../templates/repository.erb'))
120
+ repository = Erubis::Eruby.new(template).result(binding)
121
+
122
+ path = File.join('src', 'repositories', basename+'.repository.ts')
123
+ target.write path, repository
124
+ end
125
+
126
+ # produce model.index.ts
127
+ index = Dir["#{target}/src/models/*.model.ts"].sort.
128
+ map {|file| "export * from './#{File.basename(file, '.ts')}';"}.
129
+ join("\n") + "\n"
130
+ target.write 'src/models/index.ts', index
131
+
132
+ # produce repositories.index.ts
133
+ index = Dir["#{target}/src/repositories/*.repository.ts"].sort.
134
+ map {|file| "export * from './#{File.basename(file, '.ts')}';"}.
135
+ join("\n") + "\n"
136
+ target.write 'src/repositories/index.ts', index
137
+ end
@@ -0,0 +1,14 @@
1
+ import {inject} from '@loopback/core';
2
+ import {juggler} from '@loopback/repository';
3
+ import * as config from './<%= @adapter %>.datasource.json';
4
+
5
+ export class Sqlite3DataSource extends juggler.DataSource {
6
+ static dataSourceName = '<%= @adapter %>';
7
+
8
+ constructor(
9
+ @inject('datasources.config.<%= @adapter %>', {optional: true})
10
+ dsConfig: object = config,
11
+ ) {
12
+ super(dsConfig);
13
+ }
14
+ }
@@ -0,0 +1,42 @@
1
+ <%
2
+ imports = %w{Entity property model}
3
+ imports << 'belongsTo' unless @belongs_to.empty?
4
+ imports << 'hasMany' unless @has_many.empty?
5
+ %>
6
+ import {<%= imports.join(', ') %>} from '@loopback/repository';
7
+ <% @belongs_to.merge(@has_many).each do |name, value| %>
8
+ import {<%= value %>} from './<%= name %>.model';
9
+ <% end %>
10
+
11
+ @model({settings: {<%= @adapter %>: {table: '<%= @table_name %>'}}})
12
+ export class <%= @class_name %> extends Entity {
13
+ @property({
14
+ type: 'number',
15
+ id: true
16
+ })
17
+ id: number;
18
+ <% @table.each do |attr, value| %>
19
+
20
+ <% if @belongs_to.keys.any? {|key| "#{key}_id" == attr} %>
21
+ @belongsTo(() => <%= @belongs_to[attr.sub(/_id/, '')] %>, {keyTo: 'id'})
22
+ <% else %>
23
+ @property({
24
+ type: '<%= value %>'
25
+ })
26
+ <% end %>
27
+ <%= attr %>: <%= value %>;
28
+ <% end %>
29
+ <% @has_many.each do |name, value| %>
30
+
31
+ @hasMany(() => <%= value %>, {keyTo: '<%= @class_name.downcase %>_id'})
32
+ <%= name.pluralize %>: <%= value %>[];
33
+ <% end %>
34
+
35
+ getId() {
36
+ return this.id;
37
+ }
38
+
39
+ constructor(data?: Partial<<%= @class_name %>>) {
40
+ super(data);
41
+ }
42
+ }
@@ -0,0 +1,15 @@
1
+ import {DefaultCrudRepository, juggler} from '@loopback/repository';
2
+ import {<%= @class_name %>} from '../models';
3
+ import {Sqlite3DataSource} from '../datasources';
4
+ import {inject} from '@loopback/core';
5
+
6
+ export class <%= @class_name %>Repository extends DefaultCrudRepository<
7
+ <%= @class_name %>,
8
+ typeof <%= @class_name %>.prototype.id
9
+ > {
10
+ constructor(
11
+ @inject('datasources.sqlite3') dataSource: Sqlite3DataSource,
12
+ ) {
13
+ super(<%= @class_name %>, dataSource);
14
+ }
15
+ }
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails2lb4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sam Ruby
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ansi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erubis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Builds a loopback4 datasource, model, and repository from Rails schema.rb,
42
+ database.yml, and model sources
43
+ email:
44
+ - rubys@intertwingly.net
45
+ executables:
46
+ - rails2lb4
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - LICENSE
51
+ - README.md
52
+ - bin/rails2lb4
53
+ - lib/rails2lb4.rb
54
+ - templates/datasource.erb
55
+ - templates/model.erb
56
+ - templates/repository.erb
57
+ homepage: http://github.com/rubys/rails2lb4
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.7.4
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Convert Rails model to loopback4
81
+ test_files: []