I have a library module (lib) with functions in which variables from another module (const) are used. I now want to test the functions from the lib module in a test module. I have tried changing the variables from the const module for certain tests. I am not sure if this is even possible. Here is the code:
const Module:
xquery version "3.1" encoding "utf-8";
module namespace const = "Constant";
declare variable $const:numbers:=
<numbers>
<value s='one'>1</value>
<value s='two'>2</value>
<value s='three'>3</value>
<value s='four'>4</value>
<value s='five'>5</value>
<value s='other'></value>
</numbers>;
lib Module:
xquery version "3.1" encoding "utf-8";
module namespace lib = "Library";
import module namespace con="Constant" at "const.xqm";
declare function lib:inc5($val as xs:string) as xs:integer {
5+xs:integer($con:numbers//value[#s=$val])
};
test Module:
xquery version "3.1" encoding "utf-8";
module namespace test='http://basex.org/modules/xqunit-tests';
import module namespace con="Constant" at "const.xqm";
import module namespace lib="Library" at "lib.xqm";
declare %unit:test function test:inc5_add_one() {
unit:assert-equals(lib:inc5('one'), 6)
};
declare %unit:test function test:inc5_set_other_as_10_add_ten() {
(: replace node $con:numbers//value[#s='other'] with <value s='ten'>10</value> :)
(:
$con:numbers=<numbers>
<value s='one'>1</value>
<value s='two'>2</value>
<value s='three'>3</value>
<value s='four'>4</value>
<value s='five'>5</value>
<value s='ten'>10</value>
</numbers>,
:)
unit:assert-equals(lib:inc5('ten'), 15)
};
I wanted to replace the node <value s='other'></value> with <value s='ten'>10</value> in the test:inc5_set_other_as_10_add_ten in order to test lib:inc5('ten') with the expected value 15.
What I have tried is resetting $con:numbers or changing the value with replace node with statement. But neither of these works.
My question is if it is somehow possible to change $const:numbers at this point so that it is used the next time lib:inc5 is called.
Please note that it’s not possible to changes the values of variables in XQuery and functional languages in general. Instead, you can pass on the result of an update expression to another operation. Your example could be rewritten as follows:
lib Module:
declare function lib:inc5($val as xs:string, $context as element()) as xs:integer {
5 + xs:integer($context//value[#s = $val])
};
test Module:
declare %unit:test function test:inc5() {
let $updated := $con:numbers update {
replace node .//value[#s = 'other'] with <value s='ten'>10</value>
}
return unit:assert-equals(lib:inc5('ten', $updated), 15)
};
The new lib:inc5 function has two parameters, one for the string to be found and another one for the context element.
The test function performs an update on the $con:numbers element, the result is passed on to the lib function, and the result is compared with the expected value.
Related
Say I have two lua modules, like this.
Filename: my/lua/app/caller.lua
Module name: my.lua.app.caller
local reflect = require('my.lib.reflect')
-- should return "my.lua.app.caller"
reflect.get_caller_module_name()
Filename: my/lib/reflect.lua
Module name: my.lib.reflect
M = {}
function M.get_caller_module_name()
-- magic here?
return module_name
end
return M
Now running my.lua.app.caller should allow it to get its own module name, my.lua.app.caller. Is this doable in Lua?
(I realize that I can get the module name by inserting local module_name, _ = ... as the very first line of the caller's module, but I want to be able to do this without this without needing any special modifications to the caller's module.)
I'm using Poco::LoggingConfigurator library for logging, using Poco::XMLConfiguration to configure logging properties. I want to use an environment variable in path value of logging configuration xml file. How to do it in xml config file?
This is the xml configuration file i'm using now.
<logging>
<channels>
<logFileChannel>
<class>FileChannel</class>
<path>/logs/agent-xfs.log</path>
<rotation>1 M</rotation>
<archive>timestamp</archive>
<compress>true</compress>
<purgeCount>60</purgeCount>
</logFileChannel>
</channels>
<loggers>
<root>
<channel>logFileChannel</channel>
<level>debug</level>
</root>
</loggers>
I want to define path variable value using environment variable like follows,
${ENV_SAMPLE_VARAIBLE}/logs/agent-xfs.log
You can refer to environment variables using ${system.env.NAME}, e.g.:
<path>${system.env.LOGPATH}/agent-xfs.log</path>
In order for ${system.env.LOGPATH} to resolve you'll need to have a Poco::Util::LayeredConfiguration containing both a Poco::Util::SystemConfiguration and your Poco::Util::XMLConfiguration:
Poco::AutoPtr<Poco::Util::LayeredConfiguration> pConfig = new Poco::Util::LayeredConfiguration;
pConfig->add(new Poco::Util::SystemConfiguration, 100, false, false);
pConfig->add(new Poco::Util::XMLConfiguration(configFilePath.toString()), 0, false, false);
LoggingConfigurator loggingConfigurator; loggingConfigurator.configure(pConfig);
Note that Poco::Util::Application would do that automatically if you were using it to handle the configuration.
I am using Roxy to manage my project. Also using MarkLogic 8.0-6.1
I am trying to submit a searchTerm, and return a custom formatted search:snippet
Here are the complete steps that I am taking:
./../roxy/ml new test-app --server-version=8 --app-type=rest
Configure my build.properties
cd test-app/
./ml local bootstrap
Now I have my project Structure.
Create File - test-app/rest-api/ext/show-search.xqy
xquery version "1.0-ml";
module namespace ss = "http://marklogic.com/rest-api/resource/show-search";
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
declare
function ss:get(
$context as map:map,
$params as map:map
) as document-node()*
{
map:put($context, "output-types", "application/json"),
map:put($context, "output-status", (200, "OK")),
let $search-term := map:get($params, "searchTerm")
let $query := search:search($search-term,
<options xmlns="http://marklogic.com/appservices/search">
<transform-results apply="raw"/>
</options>
)
return document {$query}
};
(:
:)
declare
function ss:put(
$context as map:map,
$params as map:map,
$input as document-node()*
) as document-node()?
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (201, "Created")),
document { "PUT called on the ext service extension" }
};
(:
:)
declare
function ss:post(
$context as map:map,
$params as map:map,
$input as document-node()*
) as document-node()*
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (201, "Created")),
document { "POST called on the ext service extension" }
};
(:
:)
declare
function ss:delete(
$context as map:map,
$params as map:map
) as document-node()?
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (200, "OK")),
document { "DELETE called on the ext service extension" }
};
The above GET request uses the transform-results apply=raw option, deploys, and functions properly (I have some test documents).
However I do not want to return the whole document, I want to return a whole section of the json that had a match, no matter where in that seciton the match happened (lower levels)
So I try to write my own snipper
Create File - test-app/rest-api/ext/show-search-snipper.xqy
xquery version "1.0-ml";
module namespace sss = "http://marklogic.com/rest-api/resource/show-search-snipper";
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
declare
function sss:my-snippet(
$result as node(),
$ctsquery as schema-element(cts:query),
$options as element(search:transform-results)?
) as element(search:snippet)
{
<search:snippet>
</search:snippet>
};
I then update the search:search call to the following
let $query := search:search($search-term,
<options xmlns="http://marklogic.com/appservices/search">
<transform-results apply="my-snippet" ns="http://marklogic.com/rest-api/resource/show-search-snipper" at="show-search-snipper.xqy"/>
</options>
)
Now I should have everything I need (I think)
I run the deploy ./ml local deploy rest
and get the following
Minty-linux test-app # ./ml local deploy rest Loading REST properties
in /opt/this-is-a-test/test-app/rest-api/config/properties.xml Loading
REST options in /opt/this-is-a-test/test-app/rest-api/config/options
Loading REST extensions from /opt/this-is-a-test/test-app/rest-api/ext
ERROR: 400 "Bad Request" ERROR: {"errorResponse":{"statusCode":400,
"status":"Bad Request", "messageCode":"RESTAPI-INVALIDCONTENT",
"message":"RESTAPI-INVALIDCONTENT: (err:FOER0000) Invalid content:
invalid show-search-snipper extension: show-search-snipper either is
not a valid module or does not provide extension functions (delete,
get, put, post) in the
http://marklogic.com/rest-api/resource/show-search-snipper
namespace"}}
So I tried moving the show-search-snipper.xqy file up 1 level (to test-app/rest-api/show-search-snipper.xqy`
Run the deployment
Deployment Works No errors
Hit the URL and receive the following
500 Internal Server Error
INTERNAL ERROR
RESTAPI-INVALIDREQ: (err:FOER0000) Invalid request: reason: Extension
show-search does not exist. . See the MarkLogic server error log for
further detail.
Although I know the extension was created properly, since it worked fine before the introduction of the custom snip function. (with apply="raw")
Any thoughts how I can apply my custom snip function or what I am doing wrong in deployment?
Should you decide to stick with a custom snippeter:
It looks like Roxy is trying to treat it your snippeter module as a resource extension, which it is not. Your snippeter should be just a vanilla module in the modules db.
IDK how to configure Roxy, unfortunately, but what you're aiming for is to get Roxy to either install it using PUT /v1/ext/directories/asset or a straight up insert (`PUT /v1/documents) on your modules db. See http://docs.marklogic.com/REST/PUT/v1/ext/[directories]/[asset].
Assuming Roxy uses /ext, then the path to your snippeter would NOT be the unqualified path you have in your options. It would be an absolute path rooted at /ext/. See http://docs.marklogic.com/guide/rest-dev/search#id_72390.
There's a simpler way -- you can do this with the extract-document-data search option.
I set up some sample data to work with like this:
xquery version "1.0-ml";
for $i in (1 to 10)
return
xdmp:document-insert(
'/test-content-' || $i || '.json',
xdmp:unquote('{ "important": { "foo": 1, "bar": 2 }, "not-important": { "stuff": 3, "blah": 4 } }')
)
Having bootstrapped and deployed modules, I can get search results at http://localhost:8040/v1/search. However, I can start taking more control of the search results by using stored search options. Take a look in your project at rest-api/config/options/all.xml. They were already deployed for you when you run ml local deploy modules, so you now can search using http://localhost:8040/v1/search?options=all. Since you're using JSON data, I took it one step further and ran with: http://localhost:8040/v1/search?format=json&options=all.
I added this to rest-api/config/options/all.xml:
<extract-document-data selected="include">
<extract-path>/important</extract-path>
</extract-document-data>
This tells the search options to include the specified path with all search results. After deploying and running the search again, one result looks like this:
{
"index":1,
"uri":"/test-content-6.json",
"path":"fn:doc(\"/test-content-6.json\")",
"score":0,
"confidence":0,
"fitness":0,
"href":"/v1/documents?uri=%2Ftest-content-6.json",
"mimetype":"application/json",
"format":"json",
"matches":[{"path":"fn:doc(\"/test-content-6.json\")/object-node()", "match-text":[]}],
"extracted":{
"kind":"array",
"content":[
{"important":{"foo":1, "bar":2}}
]
}
},
Notice the "extracted" part at the end there -- I get the "important" JSON property, as specified in the options.
For a full list of options you can set to control search, see the Query Options Reference appendix.
How to set external environment variable as array?
If I have environment variable
SYMFONY__NSQLOOKUPD__HOSTS=["localhost:4161"]
and in config.yml:
socloz_nsq:
lookupd_hosts: %nsqlookupd.hosts%
Then I got an error:
Invalid type for path "socloz_nsq.lookupd_hosts". Expected array, but got string
I've found solution. Here it is:
in config.yml add to the imports section:
imports:
- { resource: parameters.php }
then create parameters.php file at the same directory where config.yml exists, and look at the following example:
<?php
$nsqlookupdhosts = getenv('SYMFONY__NSQLOOKUPD__HOSTS');
$nsqdhosts = getenv('SYMFONY__NSQD__HOSTS');
$container->setParameter('nsqlookupd.hosts.parsed', explode(',', $nsqlookupdhosts));
$container->setParameter('nsqd.hosts.parsed', explode(',', $nsqdhosts));
use comma as delimiter in environment variable (you are not restricted to comma, use any)
SYMFONY__NSQLOOKUPD__HOSTS=localhost:4161,some.server:2222
You can use a built-in "json" environment variable processor to decode a JSON string into an array:
SYMFONY__NSQLOOKUPD__HOSTS='["localhost:4161"]'
$nsqlookupdhosts: '%env(json:SYMFONY__NSQLOOKUPD__HOSTS)%'
Folks, I'm trying to do something that I thought ought to be simple, but I must be doing something wrong. I'm trying to simply have a clear structure in my meteor application which uses Typescript.
Here are my requirements:
All interfaces are available in both client and server
Some class implementations are only available on the server
I don't want to rely on file load order for my application to work properly
I need my own module to not clash with global objects (such as the Position class for example)
I need to have one monolithic include file for server, one for both client and server and one for client (don't want to have 10s of includes on top of my files)
The setup that I have right now is this
server
server-book.ts
client
shared
collections.ts
definitions
server
include.d.ts (includes all .d.ts files in this folder)
server-book.d.ts (server specific implementation of book)
client
shared
include.d.ts (includes all .d.ts files here)
book.d.ts (book interface definition)
collections.d.ts
In each .d.ts file I have
module MyModule {
interface Bla {}
};
In each .ts file that defines a class I have:
module MyModule {
export class MyBla implements Bla {};
}
All .d.ts files generated for classes are generated by tsc -d.
No .ts files are being included via ///<reference> rather only .d.ts files.
Now, when I run this, I get an error that MyModule is undefined:
/// <reference path="shared/include.d.ts"/>
/// <reference path="server/include.d.ts"/>
Meteor.startup(() => {
var temp = new MyModule.ServerBook();
});
The error occurs right on MyModule.
What am I doing wrong? What should be the proper setup here?
Thanks!
I have dealt with this issue on my blog. I decided to use the evil eval command, since it gave me the easiest possibility of using modules till something more sophisticated appears.
File /lib/foo.ts is position in the subdirectory since it has to be loaded before Bar.
eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module
module Hugo {
export class Foo {
foo():string {
return 'foo'
}
}
}
File /bar.ts
/// <reference path="lib/foo.ts"/>
eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module
module Hugo {
export class Bar extends Foo {
bar () : string {
return 'bar';
}
}
}
File /test.ts
/// <reference path="lib/foo.ts"/>
/// <reference path="bar.ts"/>
var m = new Hugo.Bar();
console.log(m.bar());
console.log(m.foo());
As mentioned here, for classes, the solution is even simpler:
class ExportedClass {
variable : int;
}
this.ExportedClass = ExportedClass;
Definition files should use the declare keyword. You would normally get an error if you didn't use this keyword.
declare module MyModule {
export interface Bla {}
}
And
declare module MyModule {
export class MyBla implements Bla {
}
}
It is also worth checking that the ServerBook class has the export keyword (just like MyBla in your examples).
After lot of trial and errors, here are my findings so far :
Using typescript "module" keyword doesn't get well with Meteor. I think at the moment you cannot use it (or the workarounds are too complicated for me).
However, here is what you can do :
Let say that you have package A where you want to define a class ClassToExport which you want to make public.
class ClassToExport {
getFoo(){
return "foo";
}
}
Please note that you can't write this.ClassToExport = ClassToExport and
api.export('ClassToExport') or else ClassToExport won't be available in the global scope of package A, hence the need for a module/namespace for exporting your class, which we will see next.
Now, for the class to be available for the consumers of your package, you have to create a namespace, which will be the equivalent of the "module" typescript keyword for internal module.
So let's write :
declare var packageA; //so that the compiler doesn't complain about undeclared var
packageA = packageA || {}; //so that this namespace can be reused for the entire package
packageA.ClassToExport = ClassToExport; //the actual export
Now, don't forget to write
api.export('packageA') in the package.js of package A
If you have a package B where you want to use ClassToExport, you write in package B:
var cte = new packageA.ClassToExport();
without forgetting to api.use package A in package B's package.js
If you don't want to write the namespace each time you use the class, you can also write var ClassToExport = packageA.ClassToExport; at the top of your using file.
If you need a global class for you package only, without exporting it, then you can do instead just :
this.ClassToExport = ClassToExport
and again don't write api.export('ClassToExport'), or it won't be available in the package anymore.
This way, i think the features (export/ import) of internal typescript modules are there.
If you are not afraid of gulp build, I have prepared a typescript boilerplate project which allows you to comfortably use typescript from within your app, not depending on packages.
https://github.com/tomitrescak/meteor-boilerplate-typescript
Random idea, what about extend Meteor instead of Window.
Meteor.yournamespace = Meteor.yournamespace || {};
Meteor.yournamespace.myclass = new MyClass();
or
Meteor.yournamespace.MyClass = MyClass();
I think this is less invasive than go directly to the window object IMHO. my two cents.
now you can do Meteor.yournamespace.MyClass :P
--EDIT
Then you could create a meteor-extend.d.ts file and do something like:
/// <reference path="main.d.ts" />
declare module Meteor {
var yournamespace: any;
}
Now you can remove the <any> before Meteor and Typescript will not complaint.