Elixir: try .. rescue around decorator - macros

I am looking into Nebulex.Caching and use the followint decorator:
#decorate cacheable(cache: Cache, key: name)
def get_by_name(name, age) do
# your logic (maybe the loader to retrieve the value from the SoR)
end
It works perfectly. However, when I turn off Redis, it fails with Elixir.Redix.ConnectionError. This issue is well described here: https://github.com/cabol/nebulex_ecto/issues/6
I tried to write my own decorator and reuse the code from Nebulex.Caching:
defmodule Coups.Inventory.Cache.Decorator do
use Decorator.Define, [safe_cacheable: 1]
require Logger
def safe_cacheable(attrs, block, context) do
try do
Nebulex.Caching.cacheable(attrs, block, context)
rescue Elixir.Redix.ConnectionError ->
quote do
unquote(block)
end
end
end
end
However, it didn't change anything, and the exception was not caught. How can I achieve the expected behavior?

Related

Subject (a class) returns itself in a method

I'm doing an exercise on a course and I have to write code to make the following test pass:
it 'returns itself when exiting a journey' do
expect(subject.finish(station)).to eq(subject)
end
I've written:
class Journey
...
def finish(station)
Journey
end
...
end
I get the error:
expected: #<Journey:0x00007fd90091e7c8>
got: Journey
(compared using ==)
Diff:
## -1,2 +1,2 ##
-#<Journey:0x00007fd90091e7c8>
+Journey
It felt a bit too easy when I was writing it but I'm not sure how else to go about this. Any help would be greatly appreciated, thanks!
You're returning a class
def finish(station)
Journey
end
but you need to return an instance:
def finish(station)
Journey.new
end
But that's not good enough yet, because you need to return the same instance as the object on which the method was called on"
def finish(station)
self
end

How to pass parameters to a Progress program using database field dynamic-based rules?

I have in my database a set of records that concentrates information about my .W's, e.g. window name, parent directory, file name, procedure type (for internal treatments purposes), used to build my main menu. With this data I'm developing a new start procedure for the ERP that I maintain and using the opportunity in order to rewrite some really outdated functions and programs and implement new functionalities. Until now, I hadn't any problems but when I started to develop the .P procedure which will check the database register of a program that was called from the menu of this new start procedure - to check if it needs to receive fixed parameters to be run and its data types - I found a problem that I can't figure out a solution.
In this table, I have stored in one of the fields the parameters needed by the program, each with his correspondent data type. The problem is on how to pass different data types to procedures based only on the stored data. I tried to pre-convert data using a CASE clause and an include to check the parameter field for correct parameter sending but the include doesn't work as I've expected.
My database field is stored as this:
Description | DATATYPE | Content
I've declared some variables and converted properly the stored data into their correct datatype vars.
DEF VAR c-param-exec AS CHAR NO-UNDO EXTENT 9 INIT ?.
DEF VAR i-param-exec AS INT NO-UNDO EXTENT 9 INIT ?.
DEF VAR de-param-exec AS DEC NO-UNDO EXTENT 9 INIT ?.
DEF VAR da-param-exec AS DATE NO-UNDO EXTENT 9 INIT ?.
DEF VAR l-param-exec AS LOG NO-UNDO EXTENT 9 INIT ?.
DEF VAR i-count AS INT NO-UNDO.
blk-count:
DO i-count = 0 TO 8:
IF TRIM(programa.parametro[i-count]) = '' THEN
LEAVE blk-count.
i-count = i-count + 1.
CASE ENTRY(2,programa.parametro[i-count],CHR(1)):
WHEN 'CHARACTER' THEN
c-param-exec[i-count] = ENTRY(3,programa.parametro[i-count],CHR(1)).
WHEN 'INTEGER' THEN
i-param-exec[i-count] = INT(ENTRY(3,programa.parametro[i-count],CHR(1))).
WHEN 'DECIMAL' THEN
de-param-exec[i-count] = DEC(ENTRY(3,programa.parametro[i-count],CHR(1))).
WHEN 'DATE' THEN
da-param-exec[i-count] = DATE(ENTRY(3,programa.parametro[i-count],CHR(1))).
WHEN 'LOGICAL' THEN
l-param-exec[i-count] = (ENTRY(3,programa.parametro[i-count],CHR(1)) = 'yes').
OTHERWISE
c-param-exec[i-count] = ENTRY(3,programa.parametro[i-count],CHR(1)).
END CASE.
END.
Then I tried to run the program using an include to pass parameters (in this example, the program have 3 INPUT parameters).
RUN VALUE(c-prog-exec) ({util\abrePrograma.i 1},
{util\abrePrograma.i 2},
{util\abrePrograma.i 3}).
Here is my abrePrograma.i
/* abrePrograma.i */
(IF ENTRY(2,programa.parametro[{1}],CHR(1)) = 'CHARACTER' THEN c-param-exec[{1}] ELSE
IF ENTRY(2,programa.parametro[{1}],CHR(1)) = 'INTEGER' THEN i-param-exec[{1}] ELSE
IF ENTRY(2,programa.parametro[{1}],CHR(1)) = 'DECIMAL' THEN de-param-exec[{1}] ELSE
IF ENTRY(2,programa.parametro[{1}],CHR(1)) = 'DATE' THEN da-param-exec[{1}] ELSE
IF ENTRY(2,programa.parametro[{1}],CHR(1)) = 'LOGICAL' THEN l-param-exec[{1}] ELSE
c-param-exec[{1}])
If I suppress the 2nd, 3rd, 4th and 5th IF's from the include or use only one data type in all IF's (e.g. only CHAR, only DATE, etc.) the program works properly and executes like a charm but I need to call some old programs, which expects different datatypes in its INPUT parameters and using the programs as described OpenEdge doesn't compile the caller, triggering the error number 223.
---------------------------
Erro (Press HELP to view stack trace)
---------------------------
** Tipos de dados imcompativeis em expressao ou atribuicao. (223)
** Nao entendi a linha 86. (196)
---------------------------
OK Ajuda
---------------------------
Can anyone help me with this ?
Thanks in advance.
Looks as if you're trying to use variable parameter definitions.
Have a look at the "create call" statement in the ABL reference.
http://documentation.progress.com/output/ua/OpenEdge_latest/index.html#page/dvref/call-object-handle.html#wwconnect_header
Sample from the documentation
DEFINE VARIABLE hCall AS HANDLE NO-UNDO.
CREATE CALL hCall.
/* Invoke hello.p non-persistently */
hCall:CALL-NAME = "hello.p".
/* Sets CALL-TYPE to the default */
hCall:CALL-TYPE = PROCEDURE-CALL-TYPE
hCall:NUM-PARAMETERS = 1.
hCall:SET-PARAMETER(1, "CHARACTER", "INPUT", "HELLO WORLD").
hCall:INVOKE.
/* Clean up */
DELETE OBJECT hCall.
The best way to get to the bottom of those kind of preprocessor related issues is to do a compile with preprocess listing followed by a syntax check on the preprocessed file. Once you know where the error is in the resulting preprocessed file you have to find out which include / define caused the code that won't compile .
In procedure editor
compile source.w preprocess source.pp.
Open source.pp in the procedure editor and do syntax check
look at original source to find include or preprocessor construct that resulted in the code that does not compile.
Okay, I am getting a little bit lost (often happens to me with lots of preprocessors) but am I missing that on the way in and out of the database fields you are storing values as characters, right? So when storing a parameter in the database you have to convert it to Char and on the way out of the database you have convert it back to its correct data-type. To not do it one way or the other would cause a type mismatch.
Also, just thinking out loud (without thinking it all the way through) wonder if using OOABL (Object Oriented ABL) depending on if you Release has it available wouldn't make it easier by defining signatures for the different datatypes and then depending on which type of input or output parameter you call it with, it will use the correct signature and correct conversion method.
Something like:
METHOD PUBLIC VOID storeParam(input cParam as char ):
dbfield = cParam.
RETURN.
END METHOD.
METHOD PUBLIC VOID storeParam(input iParam as int ):
dbfield = string(iParam).
RETURN.
END METHOD.
METHOD PUBLIC VOID storeParam(input dParam as date ):
dbfield = string(dParam).
RETURN.
END METHOD.
just a thought.

FactoryGirl to_create return value

From my understanding, the return value from a factory's 'to_create' method is ignored. This means that the object returned from the 'build' or 'initialize_with' portion of the factory is the object ultimately returned when calling 'create' within a test.
In my case, I am using a variant of the Repository Pattern. I am overriding the 'to_create' portion of the factory to include a call to a repository 'save' method. This method does not modify the given object, but returns an object representing the persisted form of the original.
However, the instance returned from the 'build' block is returned from the factory, and not the instance created in the 'to_create' block. In my code, this means the "unpersisted" form of the object is returned, not the object with updated attributes (e.g. 'id') from the saving action.
Is there a way of forcing the return value of 'create' to be either the result of the 'to_create' block or some value generated within that block?
class Foo
attr_accessor :id, :name
...
end
class FooRepository
def self.create(name)
Foo.new(name) # this object is not yet persisted and has no .id
end
def self.save(foo)
# this method must not guarantee that the original Foo instance
# will always be returned
...
updated_foo # this is a duplicate of the original object
end
...
end
FactoryGirl.define do
factory :foo, class: FooRepository do
# create an example Foo
initialize_with { FooRepository.create(name: "Example") }
# save the Foo to the datastore, returning what may be a duplicate
to_create {|instance| FooRepository.save(instance)}
end
end
describe FooRepository do
it "saves the given Foo to the datastore" do
foo = create(:foo)
foo.id #=> nil
...
end
end
I don't have an answer for you beyond "raise an issue", sorry.
The default to_create callback looks like this:
$ grep to_create lib/factory_girl/configuration.rb
to_create {|instance| instance.save! }
The main problem is that ActiveRecord modifies itself in place when you call save! on it. FactoryGirl will ignore any new objects that are returned from to_create.
A quick hack if you want to override the default create strategy:
module FactoryGirl
module Strategy
class Create
def association(runner)
runner.run
end
def result(evaluation)
evaluation.object.tap do |instance|
evaluation.notify(:after_build, instance)
evaluation.notify(:before_create, instance)
instance = evaluation.create(instance) # <-- HACK
evaluation.notify(:after_create, instance)
end
end
end
end
end
... Or do this to your to_create hook to mimic Rails' in-place modification:
to_create do |record|
new_record = YourRepositoryHere.new.create(record)
record.attributes = new_record.attributes # For example
new_record # Return the record just in case the bug is fixed
end
Best of luck. :(

How do you write an empty while loop in Coffeescript?

I'm trying to translate some old code to Coffeescript. But there is no direct translation for:
while ( doWork() ) {}
"while doWork()" with nothing after it results in a syntax error.
while doWork() then
Should do the trick
using then is probably the canonical solution since it is explicitly meant for separating the condition from the (in this case empty) body. Alternatively you can write
while doWork()
;#
(the # keeps vim syntax highlighting from flagging it as an error)
I also like the continue while doWork() solution, but I strongly advise against any other form of expression while doWork() mentioned in the comments since when this is the last statement of a function it will become a list constructor:
_results = [];
while (doWork()) {
_results.push(expression);
}
return _results;

; expected but <place your favourite keyword here> found

I'm trying to write a class for a scala project and I get this error in multiple places with keywords such as class, def, while.
It happens in places like this:
var continue = true
while (continue) {
[..]
}
And I'm sure the error is not there since when I isolate that code in another class it doesn't give me any error.
Could you please give me a rule of thumb for such errors? Where should I find them? are there some common syntactic errors elsewhere when this happens?
It sounds like you're using reserved keywords as variable names. "Continue", for instance, is a Java keyword.
You probably don't have parentheses or braces matched somewhere, and the compiler can't tell until it hits a structure that looks like the one you showed.
The other possibility is that Scala sometimes has trouble distinguishing between the end of a statement with a new one on the next line, and a multi-line statement. In that case, just drop the ; at the end of the first line and see if the compiler's happy. (This doesn't seem like it fits your case, as Scala should be able to tell that nothing should come after true, and that you're done assigning a variable.)
Can you let us know what this code is inside? Scala expects "expressions" i.e. things that resolve to a particular value/type. In the case of "var continue = true", this does not evaluate to a value, so it cannot be at the end of an expression (i.e. inside an if-expression or match-expression or function block).
i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
}
This is a problem, as the function block is an expression and needs to have an (ignored?) return value, i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
()
}
() => a value representing the "Unit" type.
I get this error when I forget to put an = sign after a function definition:
def function(val: String):Boolean {
// Some stuff
}