Giter Site home page Giter Site logo

Comments (7)

joshleitzel avatar joshleitzel commented on July 2, 2024

Sorry for the delay in getting back to you on this.

The generator now works for the most part, but it fails for models that don't inherit from ApplicationModel (my base model that inherits from ActiveRecord::Base). I realize I previously told you that all my models inherit from ApplicationModel, but that's actually not true—my apologies.

I've got a few "pseudo-models" that don't inherit from any class, that just act as models for certain purposes in my application. One such pseudo-model looks like this:

class UserRegistration
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming
...

For what it's worth, this is not a fringe case: it's something I've seen other devs do and there are many blog posts and StackOverflow questions about it.

The other failure I'm seeing is my omniauth-identity model, which looks like this:

class Identity < OmniAuth::Identity::Models::ActiveRecord
...

These models all produce errors like this:

Errno::ENOENT: No such file or directory @ rb_sysopen - ~/app/models/.rb
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/file_reader.rb:6:in `initialize'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/file_reader.rb:6:in `open'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/file_reader.rb:6:in `read'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_reader.rb:69:in `read_file'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_reader.rb:31:in `load_parent_class'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_reader.rb:23:in `sandbox_model'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_reader.rb:15:in `klass'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_reader.rb:10:in `parse'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_schema/assemble.rb:161:in `get_model'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_schema/assemble.rb:36:in `block in run'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_schema/assemble.rb:35:in `map'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/model_schema/assemble.rb:35:in `run'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/generate.rb:17:in `generate_model_schema'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/generate.rb:40:in `create_template'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/generate.rb:11:in `initialize'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/task.rake:5:in `new'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/task.rake:5:in `block (2 levels) in <top (required)>'
~/.rvm/gems/ruby-2.1.0@gemset/bin/ruby_executable_hooks:15:in `eval'

Using the code on master, when I don't add an initializer to configure ActiveMocker, I am able to run the mock generation for the most part, except for these failures. However, when I add a configure block as you suggest, the generator immediately fails:

ActiveMocker.configure do |config|
  config.model_base_classes = %w[ ActiveRecord::Base ApplicationModel ]
end
rake aborted!
ActiveMocker::Config #schema_file must be specified!
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/config.rb:30:in `block in check_required_settings'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/config.rb:29:in `each'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/config.rb:29:in `check_required_settings'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/config.rb:16:in `set'
~/.rvm/gems/ruby-2.1.0@gemset/bundler/gems/active_mocker-e5c2285ad9c4/lib/active_mocker/public_methods.rb:27:in `configure'
~/app/config/initializers/active_mocker.rb:1:in `<top (required)>'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:241:in `load'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:241:in `block in load'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:232:in `load_dependency'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:241:in `load'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/engine.rb:648:in `block in load_config_initializer'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/notifications.rb:161:in `instrument'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/engine.rb:647:in `load_config_initializer'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/engine.rb:612:in `block (2 levels) in <class:Engine>'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/engine.rb:611:in `each'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/engine.rb:611:in `block in <class:Engine>'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:30:in `instance_exec'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:30:in `run'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:55:in `block in run_initializers'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:44:in `each'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:44:in `tsort_each_child'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/initializable.rb:54:in `run_initializers'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/application.rb:288:in `initialize!'
~/app/config/environment.rb:5:in `<top (required)>'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:247:in `require'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:247:in `block in require'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:232:in `load_dependency'
~/.rvm/gems/ruby-2.1.0@gemset/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:247:in `require'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/application.rb:264:in `require_environment!'
~/.rvm/gems/ruby-2.1.0@gemset/gems/railties-4.1.1/lib/rails/application.rb:367:in `block in run_tasks_blocks'
~/.rvm/gems/ruby-2.1.0@gemset/bin/ruby_executable_hooks:15:in `eval'
~/.rvm/gems/ruby-2.1.0@gemset/bin/ruby_executable_hooks:15:in `<main>'

Also, looking at the mocks that were successfully generated, I think this behavior is not ideal. Take these two models:

class ApplicationModel < ActiveRecord::Base
  def to_s
    name
  end
end

class UserModel < ActiveRecord::Base; end

ActiveMocker will create a mock for each of these classes, but the UserModel mock does not know anything about ApplicationModel#to_s, so the mock is incomplete. This is a contrived example, of course, but the whole point of an ApplicationModel is to share core functionality throughout all the models—functionality which is missing from all of the mocks.

Here's a scheme I think might alleviate all of these inheritance problems and provide higher-fidelity mocks. Consider these models:

# base model
class ApplicationModel < ActiveRecord::Base; end

# single-table inheritance models
class User < ApplicationModel; end

class Admin < User; end

class Moderator < User; end

# pseudo-models
class UserRegistration; end

class AdminRegistration < UserRegistration; end

The generator will consider the models in this order, because of their filenames: Admin, AdminRegistration, ApplicationModel, Moderator, User, UserRegistration.

  1. First, process Admin and see that it inherits from User, so we should first make the mock of User. In order to make the mock of User, we must first make the mock of ApplicationModel. So the first mock generated will actually be ApplicationModelMock < ActiveMocker::Mock::Base. Then UserMock will be generated, but its parent should be set to ApplicationModelMock so that it behaves just like the normal model would, inheriting from ApplicationModel. Finally, generate the Admin mock and set its parent to UserMock.
  2. Next, process AdminRegistration. To do so, first process UserRegistration. Since that class doesn't inherit from anything, we can stop processing it and stop processing AdminRegistration. I don't think anybody would expect a mock to be generated for a pseudo-model.
  3. Next, process ApplicationModel. It's already been processed and mocked, so move on.
  4. Next, process Moderator. It inherits from User, which has already been processed/mocked, so just generate the mock and set its parent to UserMock.
  5. Next, process User. It's already been processed mocked, so move on.
  6. Next, process UserRegistration. It's already been processed and ignored, so stop.

At the end you would have the following mocks:

class AdminMock < UserMock; end
class ApplicationModelMock < ActiveMocker::Mock::Base; end
class ModeratorMock < UserMock; end
class UserMock < ApplicationModelMock; end

This would preserve the object hierarchy and create better mocks that have all the mocked methods of their parents. I'm not sure how difficult this would be to implement with the current code base, but I think it would be an awesome improvement!

from active_mocker.

zeisler avatar zeisler commented on July 2, 2024

Thank you for your detail and examples it's very helpful.

To address the pseudo-models I can't see the use case for creating mocks out of those classes. It looks like those type of model could be used in units tests. Maybe there is something I am not considering, at a minimum it should pass over the models and ignore them.

I agree with your last example in preserving the object hierarchy. I think this is a much better design and would like to go forward with it. This will take some reworking of things, but I don't see any technical barriers l like I had with the last change (having to use ruby parse and unparse to modify the source code before eval). Where I am employed I would like to refactor some of our models to use STI, so I will have some real use cases to work from.

from active_mocker.

zeisler avatar zeisler commented on July 2, 2024

Also when setting model_base_classes the default setting have not been loaded yet, so it breaks. You can try adding require 'active_mocker/railtie' to the top of config/initializers/active_mocker.rb but it will it need some refining.

from active_mocker.

GeekOnCoffee avatar GeekOnCoffee commented on July 2, 2024

I'm also running into the /app/models/.rb issue, though I'm not completely sure what model it's hitting it on. I could see not wanting to generate them for non-ActiveRecord classes, but it should probably gracefully skip them.

from active_mocker.

zeisler avatar zeisler commented on July 2, 2024

Test out the latest commit 0ba96c7. All feature should be working let me know if not.

Use gem 'active_mocker', github: 'zeisler/active_mocker'

from active_mocker.

zeisler avatar zeisler commented on July 2, 2024

Released 1.7.beta1
gem 'active_mocker', '~>1.7.beta1'

from active_mocker.

zeisler avatar zeisler commented on July 2, 2024

Fixed with release of 1.7

from active_mocker.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.