Why does Gambas give me an error after I Dim a variable after a function call? - gambas

I'm playing around with gambas.
This code gives me the error "unexpected dim in FMain.class:6"
Public Sub Form_Open()
Print "this won't work"
Dim nickname As String = "gambas"
Print "Your new name is " & nickname
End
This code doesn't, and runs fine:
Public Sub Form_Open()
Dim nickname As String = "gambas"
Print "Your new name is " & nickname
End
Does gambas have requirements where variables are declared like pascal? I can't find any mention of it in the documentation. Thanks.

Gambas requires all DIM statements to be placed before any executable code inside a function or Subroutine (emphasis mine):
http://gambaswiki.org/wiki/lang/dim
All DIM declarations must be in the FUNCTION or SUB before the first executable command.
So change your code to this:
Public Sub Form_Open()
Dim nickname As String = "gambas"
Print "this will work"
Print "Your new name is " & nickname
End
Gambas' requirement for forward declaration of all local variables is very old-school. Sometimes it does make it easier to make self-documenting code and it incentivizes making functions short, but if a function has many intermediate short-lived local variables that cannot be immediately initialized (e.g. inside nested loops inside a function) then it hinders readability. YMMV.

This is not required anymore since Gambas 3.12.
But I suggest to continue declaring variables at the top function. It makes the code far more readable two years later.

Related

Unapprovable RejectedAccessException when using Tuple in Jenkinsfile

I tried to use Tuple in a Jenkinsfile.
The line I wrote is def tupleTest = new Tuple('test', 'test2').
However, Jenkins did not accept this line and keep writing the following error to the console output:
No such constructor found: new groovy.lang.Tuple java.lang.String java.lang.String. Administrators can decide whether to approve or reject this signature.
...
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: No such constructor found: new groovy.lang.Tuple java.lang.Integer java.lang.String
...
When I visited the "Script Approval" configuration I could not see any scripts that pend approval.
Following this link, I tried to install and enable the "Permissive Security" plugin, but it did not help either - The error was the same.
I even tried to manually add the problematic signature to the scriptApproval.xml file. After I added it, I was able to see it in the list of approved signatures, but the error still remained.
Is there something I am doing wrong?
I had the same issue trying to use tuple on jenkins so I found out that I can simply use a list literal instead:
def tuple = ["test1", "test2"]
which is equivalent to
def (a, b) = ["test1", "test2"]
So now, instead of returning a tuple, I am returning a list in my method
def myMethod(...) {
...
return ["test 1", "test 2"]
}
...
def (a, b) = myMethod(...)
This is more or less a problem caused by groovy.lang.Tuple constructor + Jenkins sandbox Groovy mode. If you take a look at the constructor of this class you will see something like this:
package groovy.lang;
import java.util.AbstractList;
import java.util.List;
public class Tuple extends AbstractList {
private final Object[] contents;
private int hashCode;
public Tuple(Object[] contents) {
if (contents == null) throw new NullPointerException();
this.contents = contents;
}
//....
}
Groovy sandbox mode (enabled by default for all Jenkins pipelines) ensures that every invocation passes script approval check. It's not foolproof, and when it sees new Tuple('a','b') it thinks that the user is looking for a constructor that matches exactly two parameters of type String. And because such constructor does not exists, it throws this exception. However, there are two simple workarounds to this problem.
Use groovy.lang.Tuple2 instead
If your tuple is a pair, then use groovy.lang.Tuple2 instead. The good news about this class is that it provides a constructor that supports two generic types, so it will work in your case.
Use exact Object[] constructor
Alternatively, you can use the exact constructor, e.g
def tuple = new Tuple(["test","test2"] as Object[])
Both options require script approval before you can use them (however, in this case both constructors appear in the in-process script approval page).

F# constructor with <"string", str>

In this article it shows how to use the SqlCommandProvider type. The sample code has this:
use cmd = new SqlCommandProvider<"
SELECT TOP(#topN) FirstName, LastName, SalesYTD
FROM Sales.vSalesPerson
WHERE CountryRegionName = #regionName AND SalesYTD > #salesMoreThan
ORDER BY SalesYTD
" , connectionString>(connectionString)
what does the <... ,...> before the type constructor name mean and why the the
first parameter have to be a string literal? It looks like a generic but it's taking variables not types. The constructor seems to be taking in a connection string already in the <> section.
The angle brackets are the configuration for a type.
In your example, you are defining a type and creating an instance at the same type. It's clearer when the steps are separated.
Define a type.
type SalesPersonQuery = SqlCommandProvider<query, connectionString>
But to actually have an instance of the type you have to create it:
let command = new SalesPersonQuery()
Now you can use the command.Execute() rather then SalesPersonQuery.Execute().
The reason there is a constructor is because later on (at run-time) you can change the connection string to a different then the one provided in the definition, so for instance:
let command = new SalesPersonQuery(differentConnectionString)
You can find that in the documentation in configuration section:
Connection string can be overridden at run-time via constructor optional parameter
First parameter can be a path to a SQL script or a SQL query. I suppose that's the reason it's a string: how else would you like to define a SQL query?
Again, from the documentation:
Command text (sql script) can be either literal or path to *.sql file

VB.NET MVC Overload resolution failed because no accessible 'Create' accepts this number of arguments

I'm using VB.NET MVC 5 with Identity 2.0.
I've been trying to configure my Startup.Auth to automatically use a single instance of ApplicationDbContext, CustomUserManager and CustomRoleManager per request as detailed in this tutorial.
My code is as follows: (minus garbage)
Public Sub ConfigureAuth(app As IAppBuilder)
app.CreatePerOwinContext(ApplicationDbContext.Create)
' Error 135 Overload resolution failed because no accessible 'CreatePerOwinContext' can be called with these arguments:
' Extension method 'Public Function CreatePerOwinContext(Of T)(createCallback As System.Func(Of Microsoft.AspNet.Identity.Owin.IdentityFactoryOptions(Of T), Microsoft.Owin.IOwinContext, T)) As Owin.IAppBuilder' defined in 'Owin.AppBuilderExtensions': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
' Extension method 'Public Function CreatePerOwinContext(Of T)(createCallback As System.Func(Of T)) As Owin.IAppBuilder' defined in 'Owin.AppBuilderExtensions': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
app.CreatePerOwinContext(Of CustomUserManager)(CustomUserManager.Create)
' Error 136 Overload resolution failed because no accessible 'Create' accepts this number of arguments.
....
End Sub
But recieve these errors no matter what I do
Overload resolution failed because no accessible 'Create' accepts this number of arguments.
I think it's to do with me writing in VB and the example being in C#, though it infuriates me that this is a problem. My CustomUserManager is a Public Class, and the Create method is Public Shared.
Public Shared Function Create(options As IdentityFactoryOptions(Of CustomUserManager), context As IOwinContext) As CustomUserManager
Dim manager As CustomUserManager
manager = New CustomUserManager(New CustomUserStore(context.Get(Of ApplicationDbContext)()))
manager.UserValidator = New UserValidator(Of ApplicationUser, Integer)(manager)
manager.PasswordValidator = New PasswordValidator() With {
.RequiredLength = 6
}
manager.RegisterTwoFactorProvider("EmailCode",
New EmailTokenProvider(Of ApplicationUser, Integer)() With {
.Subject = "Security Code",
.BodyFormat = "Your security code is: {0}"
}
)
manager.EmailService = New EmailService()
manager.SmsService = New SmsService()
If Not options.DataProtectionProvider Is Nothing Then
manager.UserTokenProvider = New DataProtectorTokenProvider(Of ApplicationUser, Integer)(options.DataProtectionProvider.Create("ASP.NET Identity"))
End If
Return manager
End Function
Any ideas anyone? Any help is much appreciated, Cheers.
Try this
Public Sub ConfigureAuth(app As IAppBuilder)
app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
End Sub
The AddressOf operator creates a function delegate that points to the function specified by procedurename
link1
link2
If you have already updated your visual studio 2013 with Update 3. This comes with all the identity stuff and custom user manager, role manager and many more.
Create new project using MVC template and Authentication selected as Individual User Accounts using Visual Studio 2013. Then you will get created all the code same as you have already implemented using the example. You can use that classes and implementation in order to fix your issues with your custom user manager.
Check the floder App_Start >> IdentityConfig.vb
Only thing I can see in your code, you have used integer as Id rather than string. That won't be a problem if you have correctly bind EF model biding stuff.

Redirecting to a controller with sub-actions

I'm completely new to MVC, so pardon if I'm using the wrong terminology. I'm building a controller that uses the following format, to display a project, and a step within that project.
Note: I'm using MVC5 which uses the newly introduced route attributes.
'/project/1/step/2
<Route("{ProjectID}/Step/{StepNumber:int}")>
Function ProjStep(ProjectID As String, StepNumber As Integer) As String
Return String.Format("Project {0} Step {1}", ProjectID, StepNumber)
End Function
The above works as expected. But I also want to handle the case where a user only specifies the project and not the step.
'/Project/1
<Route("{ProjectID}")>
Sub Projuate(ProjectID As String)
'Automatically start the user at step 555
'How do I send the user to the URL /Project/ProjectID/Step/555
End Sub
Apologies if syntax is a bit off - I do my MVC in C#.
You can either call the step Action directly or redirect to it.
Former (this will leave URL as /Project/1):
Function Projuate(projectID As String)
Return ProjStep(projectID,555)
End Sub
Latter (will end up on /Project/1/Step/555):
Function Projuate(projectID As String)
Return Redirect(Url.Action("ProjStep", new{ ProjectID = projectID, StepNumber=555})
End Sub
I don't know whether T4MVC works with VB but I would check that out - as it means you can get rid of those magic strings and get some nice extensions for creating URLs.
EDIT NOTE: Changed Sub to Function.
Just add the default value to the route is probably the easiest way:
<Route("{ProjectID}/Step/{StepNumber:int=555}")>
Function ProjStep(ProjectID As String, StepNumber As Integer) As String
Return String.Format("Project {0} Step {1}", ProjectID, StepNumber)
End Function
p.s. I hope it comes after the int - it might be StepNumber=5:int for all I know.

How do i access the information in an hl7 message parsed with nHapi

I am learning how to use nHapi. As many have pointed out, there's not much documentation. Following this doc I've been able to parse a message using the library. But I can't figure out how to access that message using an object model (which is what I really want nHapi to do). Essentially, I want to take an HL7 message as a string and access it using the object model, in the same way that LINQ to SQL takes a database record and lets you access it as an object. I found Parsing an HL7 without a priori messageType knowledge, but it seems to be about something else because the code in the post returns a string instead of an HL7 object (like I need). In the documentation I linked to above they seem to access the parts of a message using a "query"--but I can't find the materials to query IMessages in the library.
Here is the code I'm using, with a line showing what I want to do...
Imports NHapi.Base
Imports NHapi.Base.Parser
Imports NHapi.Base.Model
Module Module1
Sub Main()
Dim msg As String = "MSH|^~\&|SENDING|SENDER|RECV|INST|20060228155525||QRY^R02^QRY_R02|1|P|2.3|QRD|20060228155525|R|I||||10^RD&Records&0126|38923^^^^^^^^&INST|||"
Dim myPipeParser As PipeParser = New PipeParser()
Dim myImsg As IMessage = myPipeParser.Parse(msg)
Dim msgType As String = myImsg.GetStructureName
Dim mySendingFacilityName As String = myImsg.getSendingFacility() //this is what I want
End Sub
Remember with HL7 messages that each segment has to end with a line return.
Also, you'll want to parse the message back to its actual type in order for the object model to be fully populated correctly (notice that when I used myPipeParser.Parse it was cast back to a QRY_R02 message type from the NHapi.Model.V23 Library). So the code should look something like this:
Imports NHapi.Model.V23.Message
Imports NHapi.Base.Parser
Imports NHapi.Base
Module Module1
Sub Main()
Dim msg As String = "MSH|^~\&|SENDING|SENDER|RECV|INST|20060228155525||QRY^R02^QRY_R02|1|P|2.3" & vbNewLine & _
"QRD|20060228155525|R|I||||10^RD&Records&0126|38923^^^^^^^^&INST|||"
Dim myPipeParser As PipeParser = New PipeParser()
Dim myImsg As QRY_R02 = myPipeParser.Parse(msg)
Dim msgType As String = myImsg.GetStructureName
Dim mySendingFacilityName As String = myImsg.MSH.SendingFacility.NamespaceID.Value
Console.WriteLine(mySendingFacilityName)
Console.ReadLine()
End Sub
End Module
I know it was a very long time ago, however I was looking for this resource very recently and found that there is nearly no documentation on how to use this API. And excellent source of examples can be found in the test part of source code in the project NHapi.NUnit.
Sources can be found here

Resources