Xtext - Validating for duplicate names - validation

I have the following grammer, but I want to do some validation on this. I want to make an error if there are duplicate names in the "players" list.
Grammer:
Football:
'Club' name=STRING playerList=PlayerList
footballObjects+=FootballObject
;
FootballObject:
Player | Coach
;
PlayerList:
players+=[Player] ( players+=[Player] )*
;
Player:
'Player' name=ID
;
I tried the following:
#Check
def checkGreetingStartsWithCapital(Football model) {
val names = newHashSet
for (g : model.playersList.players) {
if(!names.add(g.name))
error("duplicate" , g, FOOTBALLPACKAGE.Literals.FOOTBALL__PLAYERS_LIST)
}
}
But this does not work. Any ideas why?

The easiest is to mark the list entry by calling error not on the referenced player but on the playersList itself and call the error method that takes an index as well. e.g.
error("bad", playersList, MyDslPackage.Literals.PLAYERS_LIST__PLAYERS, index)

Related

R psych::statsBy() error: "'x' must be numeric"

I'm trying to do a multilevel factor analysis using the "psych" package. The first step is recommended to use the statsBy() funtion to have a correlation data:
statsBy(study2, group = "ID")
However, it gives this "Error in FUN(data[x, , drop = FALSE], ...) : 'x' must be numeric".
For the dataset, I only included a grouping variable "ID", and other two numeric variables. I ran the following line to check if the varibales are numeric.
sapply(study2, is.numeric)
ID v1 V2
FALSE TRUE TRUE
Here are the code in the tracedown of the error.But I don't know what 'x' refers here, and I noticed in line 8 and 9, the X is in captital and is lowercase in line 10.
*10.
FUN(data[x, , drop = FALSE], ...)
9.
FUN(X[[i]], ...)
8.
lapply(X = ans[index], FUN = FUN, ...)
7.
tapply(seq_len(728L), list(z = c("5edfa35e60122c277654d35b", "5ed69fbc0a53140e516ad4ed", "5d52e8160ebbe900196e252e", "5efa3da57a38f213146c7352", "5ef98f3df4d541726b1bcc48", "5debb7511e806c2a59cad664", "5c28a4530091e40001ca4d00", "5872a0d958ca4c00018ce4fe", "5c87868eddda2d00012add18", "5e80b7427567f07891655e7e", ...
6.
eval(substitute(tapply(seq_len(nd), IND, FUNx, simplify = simplify)), data)
5.
eval(substitute(tapply(seq_len(nd), IND, FUNx, simplify = simplify)), data)
4.
structure(eval(substitute(tapply(seq_len(nd), IND, FUNx, simplify = simplify)), data), call = match.call(), class = "by")
3.
by.data.frame(data, z, colMeans, na.rm = na.rm)
2.
by(data, z, colMeans, na.rm = na.rm)
1.
statsBy(study2, group = "ID")*
The dataset has 728 rows and those like "5edfa35e60122c277654d35b" are IDs. Could anyone help explain what might have gone wrong?
I had the same error, the only way was to convert the group variable to the numeric class.
Try:
study2$ID<-as.numeric(study2$ID)
statsBy(study2, group = "ID")
If dat$ID is of class character:
study2$ID<-as.numeric(as.factor(study2$ID))
statsBy(study2, group = "ID")

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 Java 8

ABC abc = eMsg.getAbcCont().stream()
.filter(cnt -> (option.geiID().equals(cnt.getId()) && option.getIdVersion() == cnt.getIdVersion()))
.collect(Collectors.toList()).get(0);
delEmsg.getAbcCont().remove(abc);
Above code is giving me en exception as
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
getAbcCont method will return the List of ABC objects.Currently my eMsg contains two object with the getAbcCont. When control reach to the .collect(Collectors.toList()).get(0); its giving the above mentioned exception. Any help suggestion must be appricaited.
This means that the result after the filter is zero elements, so you cannot do get(0).
A quick solution for this would be to first get the list of elements back, and then check if there is atleast one element.
List<ABC> list = ABC abc = eMsg.getAbcCont().stream()
.filter(cnt -> (option.geiID().equals(cnt.getId()) && option.getIdVersion() == cnt.getIdVersion()))
.collect(Collectors.toList());
if(list.size() > 0){
ABC abc = list.get(0);
}
Obviously there is a shorter way also using lambdas such as:
ABC abc = eMsg.getAbcCont().stream()
.filter(cnt -> (option.geiID().equals(cnt.getId()) && option.getIdVersion() == cnt.getIdVersion()))
.collect(Collectors.toList()).findFirst().orElse(null)
Reference: https://stackoverflow.com/a/26126636/1688441
But as User nullpointer , you might need to check if an element is found before you try to call remove() using object abc. I suspect trying to remove null from a collection might not do anything, but you could check to be sure!
if(abc != null){
delEmsg.getAbcCont().remove(abc);
}
You should do !list.isEmpty() rather than list.size() as per sonar

compilation error: record replacement of macro in Erlang

This is the directory structure.
src/
animal.hrl
people.hrl
data_animal.erl
data_people.erl
test.erl
test_macro.erl
animal.hrl
%% The record definition of animal.
-ifndef(ANIMAL).
-define(ANIMAL,true).
-record(animal,{
id,
animal_name,
age
}).
-endif.
people.hrl
%% The record definition of people.
-ifndef(PEOPLE).
-define(PEOPLE,true).
-record(people,{
id,
people_name,
age
}).
-endif.
data_animal.erl
%% The data file of animal.
-module(data_animal).
-include("animal.hrl").
%% API
-export([get/1,get_ids/0]).
get(1)->
#animal{
id=1,
animal_name="cat",
age=23
};
get(2)->
#animal{
id=2,
animal_name="dog",
age=19
};
get(3)->
#animal{
id=3,
animal_name="tiger",
age=23
};
get(4)->
#animal{
id=4,
animal_name="pig",
age=19
};
get(_)->
undefined.
get_ids()->
[1,2,3,4].
data_people.erl
%% The data file of people.
-module(data_people).
-include("people.hrl").
%% API
-export([get/1,get_ids/0]).
get(1)->
#people{
id=1,
people_name="John",
age=23
};
get(2)->
#people{
id=2,
people_name="Ken",
age=19
};
get(3)->
#people{
id=3,
people_name="Tom",
age=23
};
get(4)->
#people{
id=4,
people_name="Healthy",
age=19
};
get(_)->
undefined.
get_ids()->
[1,2,3,4].
Notice that, for data_animal.erl and data_people.erl, the parameter of get/1is the record's id of the return value, and the return value of get_ids/0 is a list of get/1's parameters.
test.erl
-module(test).
%% API
-export([get_animal_list/1,get_people_list/1]).
-include("animal.hrl").
-include("people.hrl").
get_animal_list(Age)->
Fun=fun(Id,Acc)->
case data_animal:get(Id) of
#animal{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],data_animal:get_ids()).
get_people_list(Age)->
Fun=fun(Id,Acc)->
case data_people:get(Id) of
#people{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],data_people:get_ids()).
I want to get the data of animal and people, whose ages are 23, so I write 2 functions, get_animal_list/1, get_people_list/1.
I run
1> c(data_animal),c(data_people),c(test).
{ok,test}
2> test:get_people_list(23).
[{people,3,"Tom",23},{people,1,"John",23}]
3> test:get_animal_list(23).
[{animal,3,"tiger",23},{animal,1,"cat",23}]
Suddenly, I find that the 2 functions share the same pattern. Then I attempt to write a macro get_list, and make 2 calls instead.
test_macro.erl
-module(test_macro).
%% API
-export([get_animal_list/1,get_people_list/1]).
-include("animal.hrl").
-include("people.hrl").
-define(get_list(DataMod,Record,Age),(
Fun=fun(Id,Acc)->
case DataMod:get(Id) of
#Record{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],DataMod:get_ids())
)).
get_animal_list(Age)->
?get_list(data_animal,animal,Age).
get_people_list(Age)->
?get_list(data_people,people,Age).
But I got the compile error:
4> c(test_macro).
test_macro.erl:22: syntax error before: ','
test_macro.erl:25: syntax error before: ','
test_macro.erl:4: function get_animal_list/1 undefined
test_macro.erl:4: function get_people_list/1 undefined
error
Tell me why~y~y~
Thank you all!
I have 3 questions now.
Is my code really not Erlang-like? It's extracted from my company's project. Am I still thinking in OOP? Or so do the programming guys in my company?
Thanks to #mlambrichs 's advice. It works, but I still wonder why my code get the compilation error? Is it because Erlang preprocessor is a one-pass scanner, so it fails to recognize #Record{age=Age}?
According to #mlambrichs 's suggestion, I try to change the macro
-define(get_list(DataMod, Record, Age),
[P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
DataMod:get_ids()),
P#Record.age =:= Age]
).
into a function
get_list(DataMod, Record, Age)->
[P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
DataMod:get_ids()),
P#Record.age =:= Age].
Then I get the compilation error:
syntax error before: Record
The cause of the error is a misplaced '(' which should be removed:
-define(get_list(DataMod,Record,Age), (
^^^
Fun=fun(Id,Acc)->
case DataMod:get(Id) of
#Record{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],DataMod:get_ids())
).
EDIT
You added some questions which I would like to start answering now.
Is my code really not Erlang-like?
Usage of macros. There's no real need to use macros in your situation.
In general: you would like to hide the fact what kind of records are used in people and animals. That's implementation and should be shielded by your interface. You can just define a getter function that takes care of that in the right module. Pls. read my rewrite suggestions.
It works, but I still wonder why my code get the compilation error? See top of answer.
....I try to change the macro .... You're right, that function doesn't compile. Apparently a rewrite is needed.
Like this:
get_list(DataMod, Age) ->
[ P || P = {_,_,_,A} <- lists:map(fun(Id) -> DataMod:get(Id) end,
DataMod:get_ids()),
A =:= Age].
EDIT
Taking up a rewrite. What you want is a concatenation of two list in function test (yours test/0, mine test/1). Using a comma doesn't do that for you. ;-)
test(X)->
?get_list(data_animal,X) ++
?get_list(data_people,X).
Let's fix that get_list macro as well. Your macro definition get_list has 3 parameters, where it only needs 2. Why use Record as a parameter when you already use that in get_people_list/1 and get_animal_list/1? For example, try this:
-define(get_list(DataMod, Y),
case DataMod of
data_animal -> get_animal_list(Y);
data_people -> get_people_list(Y);
_Else -> []
end
)
Overall, there is a lot of code replication in your test module. As a follow up to #yjcdll's advice, move the interface functions to animal and people to their own modules.
Let's have a look at your data modules and their get functions, as well.
I would suggest putting all people records in an array, in your case in the data_people module.
people() -> [
#people{ id=1, people_name="John", age=23 },
#people{ id=2, people_name="Ken", age=19 },
#people{ id=3, people_name="Tom", age=23 },
#people{ id=4, people_name="Healthy", age=19 } ].
Next, you would need a getter function to get only the people with a certain age:
get(Age) ->
[X || X <- people(), is_age( X, Age )].
And the is_age/2 function would be:
is_age( Person, Age ) ->
Person#people.age =:= Age.
So in module test your get_people_list/1 would get a lot simpler.
get_people_list(Age) ->
data_people:get(Age).
And so on. Always be on the lookout for code that looks pretty much the same like code you've already used somewhere. Just try to behave as a sane, lazy programmer. Lazy = good. ;-)
EDIT: OP has to stick to modules given. So a rewrite of the macro is:
-define(get_list(DataMod, Record, Age),
[P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
DataMod:get_ids()),
P#Record.age =:= Age]
).

How to find text using attribute value

I'm not quite sure what the issue is with my code, obviously I've gone wrong somewhere. Here's the code;
Then(/^the room selection should be switched to auto assign$/) do
autoassign = #browser.iframe(:id , 'iconsole-plugin-session_iframe__').div(:class , 'col-md-8 column').span(:id , 'selected_room').html
Watir::Wait.for_condition(10 , 2 , "Waiting for room to auto assign") {
autoassign.attribute_value(:id).eql?('Auto Assignment')
}
end
And here's the error;
undefined method `attribute_value' for "<span id=\"selected_room\">Auto Assignment</span>":String (NoMethodError)
autoassign is of type String. Ruby String class has no method named attribute_value.
Try removing .html from the first line so it looks likes this:
autoassign = #browser.iframe(:id , 'iconsole-plugin-session_iframe__').div(:class , 'col-md-8 column').span(:id , 'selected_room')
Watir::Wait.for_condition(10 , 2 , "Waiting for room to auto assign") {
autoassign.attribute_value(:id).eql?('Auto Assignment')
}

modify active record relation in ruby

I have my #albums which are working fine; pickung data up with albums.json.
What I'd like to do is to split this #albums in three parts.
I was thinking of something like { "ownAlbums" : [ ... ], "friendSubscriptions" : [ ... ], "otherSubscriptions" : [ ... ] } But I got several errors like
syntax error, unexpected tASSOC, expecting kEND #albums["own"] => #albums
when I tried
#albums["own"] => #albums
or
TypeError (Symbol as array index):
when I tried:
#albums[:otherSubscriptions] = 'others'
and so on.
I never tried something like this before but this .json is just a simple array ?
How can I split it in three parts ?
Or do I have to modify the active record to do so ? Because if so, I'd find another way than splitting.
Second Edit
I tried something like this and it's actually working:
#albums = [*#albums]
own = []
cnt = 0
#albums.each do |ownAlbum|
cnt = cnt.to_int
own[cnt] = ownAlbum
cnt=cnt+1
end
subs = Subscription.where(:user_id => #user.user_id)
#albums[0] = own
#albums[1] = subs
But where I have [0] and [1] I'D prefer Strings.
But then I get the error: TypeError (can't convert String into Integer):
How to get around that ?

Resources