I'd like to define a default before_save callback for any model that is a MongoMapper model. For example, with ActiveRecord I could just do this in an initializer:
module ActiveRecord
class Base
before_save :strip_attrs
private
def strip_attrs
# do stuff
end
end
end
Is it possible to do something like this with MongoMapper?
Try building an ActiveSupport::Concern plugin and then plug it into MongoMapper::Document, just like MongoMapper does for its internal plugins.
module StripOnSave
extend ActiveSupport::Concern
included do
before_save :strip_attrs
end
def strip_attrs
# ...
end
end
module MongoMapper
module Document
include StripOnSave
end
module EmbeddedDocument
include StripOnSave
end
end
Related
I have found similar questions on SO but none of them seem to give an answer that works for my case.
I have a few modules, in one of them I create a mutable struct which I want to be able to use in the others. All files are at the same level:
file_module_A.jl
file_module_B.jl
file_module_C.jl
In file_module_A.jl:
module A
mutable struct MyType
variable
end
end
In file_module_B.jl:
module B
# I need to import MyType here
end
In file_module_C.jl:
module C
# I need to import MyType here
end
I have tried the followings without success:
Using directly: using .A doesn't work
I can't use: include("./file_module_A.jl") in both B and C because when they interact between each other I get the error can't convert from Main.B.A to Main.C.A since include includes a copy of the whole code
Any ideas? Thanks in advance!
You need to use using ..A. using .A means to look for A in the current module (B in the example below), and you need an extra . to step up one module level, to Main if you run the example in the REPL:
module A
mutable struct MyType
variable
end
end
module B
using ..A: MyType
end
I have a module called Interfaces:
defmodule Interfaces do
defmacro __using__(module) do
#module unquote(module) |> List.first |> elem(1)
defmacro expose(name) do
IO.inspect params, label: "Expanding macro with: "
IO.inspect #module, label: "I need this !!"
def unquote(name)() do
IO.puts "The function has been created with exposed name"
end
end
end
end
Another module called Interfaces.MyModule :
defmodule Interfaces.MyModule do
use Interfaces, for: Something.DefinedElseWhere
expose :plop
end
But at compile time I get
** (CompileError) lib/my_module.ex:6: undefined function expose/1
I highly recommend that you read the Macros Guide on the official Elixir website. While what you're doing is possible (using quote), it is not encouraged at all.
Macros should be simple and their functionality should be broken down further in other macros and methods if the need arises. One way to do that is to use the import statement in your macro to import other macros that you need exposed in the final module:
defmodule Interface do
defmacro __using__(opts) do
quote(bind_quoted: [opts: opts]) do
import Interface
#interface_module Keyword.get(opts, :for)
end
end
defmacro expose(name) do
quote do
IO.inspect #interface_module, label: "I need this !!"
def unquote(name)() do
IO.puts "The function has been created with exposed name"
end
end
end
end
Now you can use it:
defmodule MyImplementation do
use Interface, for: AnotherModule
expose(:hello)
end
Here's another example from one of my projects, on how you should break down the implementation of large macros using helper functions and other macros.
In a system verilog design, I have a top-module, sub-module and a sub-sub module. sub-sub module instantiated in sub-module instantiated in top module.Top module also has an instance of sub-sub module.The hierarchy tree is shown below
The sub-sub module definition has some code written in a 'ifndef block like this
module sub_sub()
{
...........
`ifndef OFF
<code to avoid>
`endif
...........
}
How can I disable the code to avoid only in sub-sub module instance1 during compilation?
I used `define OFF in sub-module instance but it disables code to avoid from all instances.
The cleaner solution is to pass a parameter and use a generate-if/case statement. Example:
module sub_sub #(parameter OFF=0) ( ... );
generate
if (OFF) begin
<code to avoid>
end
endgenerate
endmodule
module sub ( ... );
...
sub_sub #( .OFF(1'b1) ) inst ( ... );
endmodule
module top ( ... );
...
sub inst0 ( ... );
sub_sub #( .OFF(1'b0) ) inst1 ( ... );
endmodule
Technically the the if (OFF) does not need to be in an explicit generate-endgenerate; it is inferred otherwise. It is recommended for human readability.
For full detail on generate blocks, refer to IEEE Std 1800-2012 ยง 27. Generate constructs
The scope of `define macros, and most other compiler directives is a compilation unit. A compilation unit is a stream of source text that a compiler parses. A macro gets defined at the point it appears in the compilation unit and is visible from that point onward.
The scopes defined by modules and other namespaces are irrelevant because macros are pre-processed before any Verilog or SystemVerilog syntax gets recognized. This means you can never have instance specific control over macro definitions.
If you want instance specific control over your code, you need to define parameters with instance specific overrides. Then you can use generate-if/case constructs to control the code you want to execute. If the generate construct is too restrictive for you, you can use procedural-if/case statements and optimization will remove branches not taken as a result of constant parameters.
The best way is to modify your sub_sub module using parameter as suggested in other answers.
However, this may not be practical if you can't edit/modify the sub_sub module, for example, it may be an encrypted IP.
In this case, one solution is to create wrapper nested module for each sub_sub module. You can do as follows:
// Wrapper for sub_sub with OFF defined
module sub_sub_wrapper1;
`define OFF
`include "sub_sub.v"
`undef OFF
endmodule
// Wrapper for sub_sub without OFF defined
module sub_sub_wrapper2;
`include "sub_sub.v"
endmodule
////////////////
module sub;
sub_sub_wrapper1 subsub1();
endmodule
module top;
sub sub1();
sub_sub_wrapper2 subsub2();
endmodule
Quick sample
In this case of course I am assuming you are able to edit your top and sub module. And just note that nested module is only supported in system-verilog.
A program I am working on performs calculations that involve objects that can only have several possible sets of values. These parameter sets are read from a catalogue file.
As an example say the objects are representing cars and the catalogue contains a value set {id: (name, color, power, etc.)} for each model. There are however many of these catalogues.
I use Matlab's unittest package to test if the calculations fail for any of the property combinations listed in the catalogues. I want to use this package, because it provides a nice list of entries that failed. I already have a test that generates a cell array of all ids for a (hardcoded) catalogue file and uses it for parameterized tests.
For now I need to create a new class for each catalogue file. I would like to set the catalogue file name as a class parameter and the entries in it as method parameters (which are generated for all class parameters), but I cannot find a way to pass the current class parameter to the local method for creating the method parameter list.
How can I make this work?
In case it is important: I am using Matlab 2014a, 2015b or 2016a.
I have a couple thoughts.
Short answer is no this can't be done currently because the TestParameters are defined as Constant properties and so can't change across each ClassSetupParameter value.
However, to me creating a separate class for each catalogue doesn't seem like a bad idea. Where does that workflow fallover for you? If desired you can still share code across these files by using a test base class with your content and an abstract property for the catalogue file.
classdef CatalogueTest < matlab.unittest.TestCase
properties(Abstract)
Catalogue;
end
properties(Abstract, TestParameter)
catalogueValue
end
methods(Static)
function cellOfValues = getValuesFor(catalog)
% Takes a catalog and returns the values applicable to
% that catalog.
end
end
methods(Test)
function testSomething(testCase, catalogueValue)
% do stuff with the catalogue value
end
function testAnotherThing(testCase, catalogueValue)
% do more stuff with the catalogue value
end
end
end
classdef CarModel1Test < CatalogueTest
properties
% If the catalog is not needed elsewhere in the test then
% maybe the Catalogue abstract property is not needed and you
% only need the abstract TestParameter.
Catalogue = 'Model1';
end
properties(TestParameter)
% Note call a function that lives next to these tests
catalogueValue = CatalogueTest.getValuesFor('Model1');
end
end
Does that work for what you are trying to do?
When you say method parameters I assume you mean "TestParameters" as opposed to "MethodSetupParameters" correct? If I am reading your question right I am not sure this applies in your case, but I wanted to mention that you can get the data from your ClassSetupParameters/MethodSetupParameters into your test methods by creating another property on your class to hold the values in Test[Method|Class]Setup and then referencing those values inside your Test method.
Like so:
classdef TestMethodUsesSetupParamsTest < matlab.unittest.TestCase
properties(ClassSetupParameter)
classParam = {'data'};
end
properties
ThisClassParam
end
methods(TestClassSetup)
function storeClassSetupParam(testCase, classParam)
testCase.ThisClassParam = classParam;
end
end
methods(Test)
function testSomethingAgainstClassParam(testCase)
testCase.ThisClassParam
end
end
end
Of course, in this example you should just use a TestParameter, but there may be some cases where this might be useful. Not sure if its useful here or not.
I'm trying to write the macro that generates a module:
defmodule GenModules do
defmacro module(name, do: body) do
quote do
defmodule unquote(String.to_atom(name)) do
unquote(body)
end
end
end
end
What I'm missing is to how to inject the 'import' statement that would refer the module the macro will be called from?
I.e., the following code:
defmodule Test do
import GenModules
module "NewModule" do
def test_call do
hello_world
end
end
def hello_world do
IO.puts "Hello"
end
end
won't compile because hello_world function is not visible from the generated NewModule.
So I need to generate
import Test
before the body of the module, somehow getting the name of the module the macro was called from. How do I do this?
Thank you,
Boris
To get the module your macro was called from you can use the special form __CALLER__. It contains a bunch of information, but you can extract the calling module like so:
__CALLER__.context_modules |> hd
But more generally I don't think what you want is possible - you cannot import a module before you finish defining it. For example:
defmodule A do
defmodule B do
import A
end
end
results in an error:
** (CompileError) test.exs:3: module A is not loaded but was defined.
This happens because you are trying to use a module in the same context it is defined.
Try defining the module outside the context that requires it.