react_on_rails 1.1.1 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -0
  4. data/.travis.yml +2 -8
  5. data/Dockerfile_tests +1 -1
  6. data/Gemfile +68 -2
  7. data/README.md +21 -15
  8. data/Rakefile +3 -109
  9. data/app/assets/javascripts/react_on_rails.js +10 -0
  10. data/docker-compose.yml +0 -6
  11. data/docs/additional_reading/webpack.md +46 -0
  12. data/docs/generator_testing.md +20 -0
  13. data/lib/generators/react_on_rails/base_generator.rb +49 -9
  14. data/lib/generators/react_on_rails/bootstrap_generator.rb +14 -29
  15. data/lib/generators/react_on_rails/dev_tests_generator.rb +30 -0
  16. data/lib/generators/react_on_rails/install_generator.rb +14 -3
  17. data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +2 -3
  18. data/lib/generators/react_on_rails/templates/base/base/client/package.json.tt +26 -23
  19. data/lib/generators/react_on_rails/templates/base/base/client/{webpack.client.hot.config.js → webpack.client.hot.config.js.tt} +3 -1
  20. data/lib/generators/react_on_rails/templates/base/base/lib/tasks/{assets.rake → assets.rake.tt} +2 -0
  21. data/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js +1 -1
  22. data/lib/generators/react_on_rails/templates/dev_tests/.rspec +2 -0
  23. data/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb +25 -0
  24. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +57 -0
  25. data/lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb +21 -0
  26. data/lib/generators/react_on_rails/templates/dev_tests/spec/spec_helper.rb +95 -0
  27. data/lib/react_on_rails/version.rb +1 -1
  28. data/rakelib/docker.rake +33 -0
  29. data/rakelib/dummy_apps.rake +29 -0
  30. data/rakelib/example_type.rb +160 -0
  31. data/rakelib/examples.rake +103 -0
  32. data/rakelib/examples_config.yml +19 -0
  33. data/rakelib/lint.rake +37 -0
  34. data/rakelib/run_rspec.rake +65 -0
  35. data/rakelib/task_helpers.rb +44 -0
  36. data/ruby-lint.yml +1 -0
  37. metadata +22 -9
  38. data/Dockerfile_ci +0 -12
  39. data/docs/generator_testing_script.md +0 -49
  40. data/lib/generators/react_on_rails/templates/client/README.md +0 -97
@@ -0,0 +1,21 @@
1
+ # Starts SimpleCov for code coverage.
2
+
3
+ if ENV["COVERAGE"]
4
+ require "simplecov"
5
+
6
+ # Using a command name prevents results from getting clobbered by other test suites
7
+ example_name = File.basename(File.expand_path("../../../.", __FILE__))
8
+ SimpleCov.command_name(example_name)
9
+
10
+ SimpleCov.start("rails") do
11
+ # Consider the entire gem project as the root
12
+ # (typically this will be the folder named "react_on_rails")
13
+ gem_root_path = File.expand_path("../../../../.", __FILE__)
14
+ root gem_root_path
15
+
16
+ # Don't report anything that has "spec" in the path
17
+ add_filter do |src|
18
+ src.filename =~ %r{\/spec\/}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,95 @@
1
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ # rubocop:disable Style/BlockComments
46
+ =begin
47
+
48
+ # These two settings work together to allow you to limit a spec run
49
+ # to individual examples or groups you care about by tagging them with
50
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
51
+ # get run.
52
+ config.filter_run :focus
53
+ config.run_all_when_everything_filtered = true
54
+
55
+ # Allows RSpec to persist some state between runs in order to support
56
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
57
+ # you configure your source control system to ignore this file.
58
+ config.example_status_persistence_file_path = "spec/examples.txt"
59
+
60
+ # Limits the available syntax to the non-monkey patched syntax that is
61
+ # recommended. For more details, see:
62
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
63
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
64
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
65
+ config.disable_monkey_patching!
66
+
67
+ # Many RSpec users commonly either run the entire suite or an individual
68
+ # file, and it's useful to allow more verbose output when running an
69
+ # individual spec file.
70
+ if config.files_to_run.one?
71
+ # Use the documentation formatter for detailed output,
72
+ # unless a formatter has already been configured
73
+ # (e.g. via a command-line flag).
74
+ config.default_formatter = 'doc'
75
+ end
76
+
77
+ # Print the 10 slowest examples and example groups at the
78
+ # end of the spec run, to help surface which specs are running
79
+ # particularly slow.
80
+ config.profile_examples = 10
81
+
82
+ # Run specs in random order to surface order dependencies. If you find an
83
+ # order dependency and want to debug it, you can fix the order by providing
84
+ # the seed, which is printed after each run.
85
+ # --seed 1234
86
+ config.order = :random
87
+
88
+ # Seed global randomization in this process using the `--seed` CLI option.
89
+ # Setting this allows you to use `--seed` to deterministically reproduce
90
+ # test failures related to randomization by passing the same `--seed` value
91
+ # as the one that triggered the failure.
92
+ Kernel.srand config.seed
93
+ =end
94
+ end
95
+ # rubocop:enable Style/BlockComments
@@ -1,3 +1,3 @@
1
1
  module ReactOnRails
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0.rc1"
3
3
  end
@@ -0,0 +1,33 @@
1
+ namespace :docker do
2
+ desc "Run Rubocop linter from docker"
3
+ task :rubocop do
4
+ sh "docker-compose run lint rake lint:rubocop"
5
+ end
6
+
7
+ desc "Run ruby-lint linter from docker"
8
+ task :ruby do
9
+ sh "docker-compose run lint rake lint:ruby"
10
+ end
11
+
12
+ desc "Run scss-lint linter from docker"
13
+ task :scss do
14
+ sh "docker-compose run lint rake lint:scss"
15
+ end
16
+
17
+ desc "Run eslint linter from docker"
18
+ task :eslint do
19
+ sh "docker-compose run lint rake lint:eslint"
20
+ end
21
+
22
+ desc "Run jscs linter from docker"
23
+ task :jscs do
24
+ sh "docker-compose run lint rake lint:jscs"
25
+ end
26
+ desc "Run all linting from docker"
27
+ task :lint do
28
+ sh "docker-compose run lint rake lint"
29
+ end
30
+ end
31
+
32
+ desc "Runs all linters from docker. Run `rake -D docker` to see all available lint options"
33
+ task docker: ["docker:lint"]
@@ -0,0 +1,29 @@
1
+ require_relative "task_helpers"
2
+ include ReactOnRails::TaskHelpers
3
+
4
+ namespace :dummy_apps do
5
+ task :dummy_app do
6
+ dummy_app_dir = File.join(gem_root, "spec/dummy")
7
+ bundle_install_in(dummy_app_dir)
8
+ dummy_app_client_dir = File.join(dummy_app_dir, "client")
9
+ sh_in_dir(dummy_app_client_dir, ["npm install",
10
+ "$(npm bin)/webpack --config webpack.server.js",
11
+ "$(npm bin)/webpack --config webpack.client.js"])
12
+ end
13
+
14
+ task :dummy_react_013_app do
15
+ dummy_app_dir = File.join(gem_root, "spec/dummy-react-013")
16
+ bundle_install_in(dummy_app_dir)
17
+ dummy_app_client_dir = File.join(dummy_app_dir, "client")
18
+ sh_in_dir(dummy_app_client_dir, ["npm install",
19
+ "$(npm bin)/webpack --config webpack.server.js",
20
+ "$(npm bin)/webpack --config webpack.client.js"])
21
+ end
22
+
23
+ task dummy_apps: [:dummy_app, :dummy_react_013_app] do
24
+ puts "Prepared all Dummy Apps"
25
+ end
26
+ end
27
+
28
+ desc "Prepares all dummy apps by installing dependencies"
29
+ task dummy_apps: ["dummy_apps:dummy_apps"]
@@ -0,0 +1,160 @@
1
+ require "rake"
2
+ require "pathname"
3
+
4
+ require_relative "task_helpers"
5
+
6
+ # Defines the ExampleType class, where each object represents a unique type of example
7
+ # app that we can generate.
8
+ module ReactOnRails
9
+ module TaskHelpers
10
+ class ExampleType
11
+ def self.all
12
+ @example_types ||= []
13
+ end
14
+
15
+ def self.namespace_name
16
+ "examples"
17
+ end
18
+
19
+ attr_reader :name, :generator_options
20
+
21
+ def initialize(name:, generator_options:)
22
+ @name = name
23
+ @generator_options = generator_options
24
+ self.class.all << self
25
+ end
26
+
27
+ def name_pretty
28
+ "#{@name} example app"
29
+ end
30
+
31
+ def server_rendering?
32
+ generator_options.include?("--server-rendering")
33
+ end
34
+
35
+ def dir
36
+ File.join(examples_dir, name)
37
+ end
38
+
39
+ def dir_exist?
40
+ Dir.exist?(dir)
41
+ end
42
+
43
+ def client_dir
44
+ File.join(dir, "client")
45
+ end
46
+
47
+ def source_package_json
48
+ File.join(gem_root, "lib/generators/react_on_rails/templates/base/base/client/package.json.tt")
49
+ end
50
+
51
+ def node_modules_dir
52
+ File.join(client_dir, "node_modules")
53
+ end
54
+
55
+ def webpack_bundles_dir
56
+ File.join(dir, "app", "assets", "javascripts", "generated")
57
+ end
58
+
59
+ def webpack_bundles
60
+ bundles = []
61
+ bundles << File.join(webpack_bundles_dir, "app-bundle.js")
62
+ bundles << File.join(webpack_bundles_dir, "server-bundle.js") if server_rendering?
63
+ bundles << File.join(webpack_bundles_dir, "vendor-bundle.js")
64
+ end
65
+
66
+ def gemfile
67
+ File.join(dir, "Gemfile")
68
+ end
69
+
70
+ def gemfile_lock
71
+ "#{gemfile}.lock"
72
+ end
73
+
74
+ def package_json
75
+ File.join(client_dir, "package.json")
76
+ end
77
+
78
+ # Gems we need to add to the Gemfile before bundle installing
79
+ def required_gems
80
+ relative_gem_root = Pathname(gem_root).relative_path_from(Pathname(dir))
81
+ ["gem 'react_on_rails', path: '#{relative_gem_root}'"]
82
+ end
83
+
84
+ # Options we pass when running `rails new` from the command-line
85
+ def rails_options
86
+ "--skip-bundle --skip-spring --skip-git --skip-test-unit --skip-active-record"
87
+ end
88
+
89
+ # Methods for retrieving the name of a task specific to the example type
90
+ %w(gen prepare clean clobber npm_install build_webpack_bundles).each do |task_type|
91
+ method = "#{task_type}_task_name" # ex: `clean_task_name`
92
+ task_name = "#{task_type}_#{name}" # ex: `clean_basic`
93
+
94
+ define_method(method) { "#{self.class.namespace_name}:#{task_name}" }
95
+ define_method("#{method}_short") { task_name }
96
+ end
97
+
98
+ def rspec_task_name_short
99
+ "example_#{name}"
100
+ end
101
+
102
+ def rspec_task_name
103
+ "run_rspec:#{rspec_task_name_short}"
104
+ end
105
+
106
+ def source_files
107
+ FileList.new(all_files_in_dir(generators_source_dir))
108
+ end
109
+
110
+ # Note: we need to explicitly declare a file we know is supposed to be there
111
+ # to indicate that the example is in need of being rebuilt in the case of its absence.
112
+ def generated_files
113
+ FileList.new(all_files_in_dir(dir)) do |fl|
114
+ fl.include(gemfile) # explicitly declared file (dependency of Gemfile.lock)
115
+ fl.include(package_json) # explicitly declared file (dependency of NPM Install)
116
+ fl.exclude(%r{client(/node_modules(.+)?)?$}) # leave node_modules folder
117
+ end
118
+ end
119
+
120
+ def generated_client_files
121
+ generated_files.exclude { |f| !f.start_with?(client_dir) }
122
+ end
123
+
124
+ # generated files plus explicitly included files resulting from running
125
+ # bundle install, npm install, and generating the webpack bundles
126
+ def prepared_files
127
+ generated_files
128
+ .include(webpack_bundles)
129
+ .include(node_modules_dir)
130
+ .include(gemfile_lock)
131
+ end
132
+
133
+ def clean_files
134
+ generated_files
135
+ end
136
+
137
+ # Assumes we are inside client folder
138
+ def build_webpack_bundles_shell_commands
139
+ webpack_command = File.join("$(npm bin)", "webpack")
140
+ shell_commands = []
141
+ shell_commands << "#{webpack_command} --config webpack.server.rails.config.js" if server_rendering?
142
+ shell_commands << "#{webpack_command} --config webpack.client.rails.config.js"
143
+ end
144
+
145
+ # Assumes we are inside a rails app's folder and necessary gems have been installed
146
+ def generator_shell_commands
147
+ shell_commands = []
148
+ shell_commands << "rails generate react_on_rails:install #{generator_options}"
149
+ shell_commands << "rails generate react_on_rails:dev_tests #{generator_options}"
150
+ end
151
+
152
+ private
153
+
154
+ # Defines globs that scoop up all files (including dotfiles) in given directory
155
+ def all_files_in_dir(p_dir)
156
+ [File.join(p_dir, "**", "*"), File.join(p_dir, "**", ".*")]
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,103 @@
1
+ # Defines tasks related to generating example apps using the gem's generator.
2
+ # Allows us to create and test apps generated using a wide range of options.
3
+ #
4
+ # Also see example_type.rb
5
+
6
+ require "yaml"
7
+ require_relative "example_type"
8
+ require_relative "task_helpers"
9
+ include ReactOnRails::TaskHelpers
10
+
11
+ namespace :examples do
12
+ # Loads data from examples_config.yml and instantiates corresponding ExampleType objects
13
+ examples_config_file = File.expand_path("../examples_config.yml", __FILE__)
14
+ examples_config = symbolize_keys(YAML.load(File.read(examples_config_file)))
15
+ examples_config[:example_type_data].each { |example_type_data| ExampleType.new(symbolize_keys(example_type_data)) }
16
+
17
+ # Define tasks for each example type
18
+ ExampleType.all.each do |example_type|
19
+ # GENERATED FILES
20
+ example_type.generated_files.each do |f|
21
+ file f => example_type.source_files do
22
+ Rake::Task[example_type.gen_task_name].invoke
23
+ end
24
+ end
25
+
26
+ # GEMFILE.LOCK
27
+ file example_type.gemfile_lock => example_type.gemfile do
28
+ bundle_install_in(example_type.dir)
29
+ end
30
+
31
+ # WEBPACK BUNDLES
32
+ example_type.webpack_bundles.each do |f|
33
+ file f => example_type.generated_client_files do
34
+ Rake::Task[example_type.build_webpack_bundles_task_name].invoke
35
+ end
36
+ end
37
+
38
+ # BUILD WEBPACK BUNDLES
39
+ task example_type.build_webpack_bundles_task_name_short => example_type.npm_install_task_name do
40
+ sh_in_dir(example_type.client_dir, example_type.build_webpack_bundles_shell_commands)
41
+ end
42
+
43
+ # NPM INSTALL
44
+ task example_type.npm_install_task_name_short => example_type.package_json do
45
+ unless uptodate?(example_type.node_modules_dir, [example_type.source_package_json])
46
+ sh_in_dir(example_type.client_dir, "npm install")
47
+ end
48
+ end
49
+
50
+ # CLEAN
51
+ desc "Cleans #{example_type.name_pretty}"
52
+ task example_type.clean_task_name_short do
53
+ example_type.clean_files.each { |f| rm_rf(f) }
54
+ end
55
+
56
+ # CLOBBER
57
+ desc "Clobbers (deletes) #{example_type.name_pretty}"
58
+ task example_type.clobber_task_name_short do
59
+ rm_rf(example_type.dir)
60
+ end
61
+
62
+ # GENERATE
63
+ desc "Generates #{example_type.name_pretty}"
64
+ task example_type.gen_task_name_short => example_type.clean_task_name do
65
+ mkdir_p(example_type.dir)
66
+ sh_in_dir(examples_dir, "rails new #{example_type.name} #{example_type.rails_options}")
67
+ append_to_gemfile(example_type.gemfile, example_type.required_gems)
68
+ bundle_install_in(example_type.dir)
69
+ sh_in_dir(example_type.dir, example_type.generator_shell_commands)
70
+ end
71
+
72
+ # PREPARE
73
+ desc "Prepares #{example_type.name_pretty} (generates example, `npm install`s, and generates webpack bundles)"
74
+ multitask example_type.prepare_task_name_short => example_type.prepared_files
75
+ end
76
+
77
+ desc "Cleans all example apps"
78
+ multitask clean: ExampleType.all.map(&:clean_task_name)
79
+
80
+ desc "Clobbers (deletes) all example apps"
81
+ task :clobber do
82
+ rm_rf(examples_dir)
83
+ end
84
+
85
+ desc "Generates all example apps"
86
+ multitask gen_all: ExampleType.all.map(&:gen_task_name)
87
+
88
+ desc "Prepares all example apps"
89
+ multitask prepare_all: ExampleType.all.map(&:prepare_task_name)
90
+ end
91
+
92
+ desc "Prepares all example apps. Run `rake -D examples` to see all available options"
93
+ multitask examples: ["examples:prepare_all"]
94
+
95
+ private
96
+
97
+ # Appends each string in an array as a new line of text in the given Gemfile.
98
+ # Automatically adds line returns.
99
+ def append_to_gemfile(gemfile, lines)
100
+ old_text = File.read(gemfile)
101
+ new_text = lines.reduce(old_text) { |a, e| a << "#{e}\n" }
102
+ File.open(gemfile, "w") { |f| f.puts(new_text) }
103
+ end