Skip to content
Permalink
Browse files

Implement join-with-separator block

Change-Id: I6d7899a36e7e2ee4dd748948a98ce6693af18650
  • Loading branch information...
lightingft authored and ewpatton committed Mar 7, 2019
1 parent b2d4a63 commit ceb27bf233d93e61ef741e9255149e1bb3e8ff8c
@@ -449,3 +449,22 @@ Blockly.Blocks['lists_lookup_in_pairs'] = {
},
typeblock: [{ translatedName: Blockly.Msg.LANG_LISTS_LOOKUP_IN_PAIRS_TITLE_LOOKUP_IN_PAIRS }]
};

Blockly.Blocks['lists_join_with_separator'] = {
// Joins list items into a single string separated by specified separator
category : 'Lists',
helpUrl : Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_HELPURL,
init : function() {
this.setColour(Blockly.LIST_CATEGORY_HUE);
this.setOutput(true, Blockly.Blocks.Utilities.YailTypeToBlocklyType("text",Blockly.Blocks.Utilities.OUTPUT));
var checkTypeList = Blockly.Blocks.Utilities.YailTypeToBlocklyType("list",Blockly.Blocks.Utilities.INPUT);
var checkTypeText = Blockly.Blocks.Utilities.YailTypeToBlocklyType("text",Blockly.Blocks.Utilities.INPUT);
this.interpolateMsg(Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_INPUT,
['SEPARATOR', checkTypeText, Blockly.ALIGN_RIGHT],
['LIST', checkTypeList, Blockly.ALIGN_RIGHT],
Blockly.ALIGN_RIGHT);
this.setTooltip(Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_TOOLTIP);
this.setInputsInline(false);
},
typeblock: [{ translatedName: Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_TITLE }]
};
@@ -432,6 +432,12 @@ Blockly.Drawer.defaultBlockXMLStrings = {
'<value name="NOTFOUND"><block type="text"><title name="TEXT">not found</title></block></value>' +
'</block>' +
'</xml>'},
lists_join_with_separator: {xmlString:
'<xml>' +
'<block type="lists_join_with_separator">' +
'<value name="SEPARATOR"><block type="text"><title name="TEXT"></title></block></value>' +
'</block>' +
'</xml>'},

component_method: [
{matchingMutatorAttributes:{component_type:"TinyDB", method_name:"GetValue"},
@@ -300,16 +300,30 @@ Blockly.Yail['lists_from_csv_table'] = function() {
return [ code, Blockly.Yail.ORDER_ATOMIC ];
};

Blockly.Yail['lists_lookup_in_pairs'] = function() {
// Lookup in pairs in list of lists (key, value).
var argument0 = Blockly.Yail.valueToCode(this, 'KEY', Blockly.Yail.ORDER_NONE) || Blockly.Yail.YAIL_FALSE;
var argument1 = Blockly.Yail.valueToCode(this, 'LIST', Blockly.Yail.ORDER_NONE) || Blockly.Yail.emptyListCode;
var argument2 = Blockly.Yail.valueToCode(this, 'NOTFOUND', Blockly.Yail.ORDER_NONE) || Blockly.Yail.YAIL_NULL;
var code = Blockly.Yail.YAIL_CALL_YAIL_PRIMITIVE + "yail-alist-lookup" + Blockly.Yail.YAIL_SPACER;
code = code + Blockly.Yail.YAIL_OPEN_COMBINATION + Blockly.Yail.YAIL_LIST_CONSTRUCTOR + Blockly.Yail.YAIL_SPACER;
code = code + argument0 + Blockly.Yail.YAIL_SPACER + argument1 + Blockly.Yail.YAIL_SPACER + argument2 + Blockly.Yail.YAIL_CLOSE_COMBINATION;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_QUOTE + Blockly.Yail.YAIL_OPEN_COMBINATION;
code = code + "any list any" + Blockly.Yail.YAIL_CLOSE_COMBINATION + Blockly.Yail.YAIL_SPACER;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_DOUBLE_QUOTE + "lookup in pairs" + Blockly.Yail.YAIL_DOUBLE_QUOTE + Blockly.Yail.YAIL_CLOSE_COMBINATION;
return [ code, Blockly.Yail.ORDER_ATOMIC ];
};
Blockly.Yail['lists_lookup_in_pairs'] = function() {
// Lookup in pairs in list of lists (key, value).
var argument0 = Blockly.Yail.valueToCode(this, 'KEY', Blockly.Yail.ORDER_NONE) || Blockly.Yail.YAIL_FALSE;
var argument1 = Blockly.Yail.valueToCode(this, 'LIST', Blockly.Yail.ORDER_NONE) || Blockly.Yail.emptyListCode;
var argument2 = Blockly.Yail.valueToCode(this, 'NOTFOUND', Blockly.Yail.ORDER_NONE) || Blockly.Yail.YAIL_NULL;
var code = Blockly.Yail.YAIL_CALL_YAIL_PRIMITIVE + "yail-alist-lookup" + Blockly.Yail.YAIL_SPACER;
code = code + Blockly.Yail.YAIL_OPEN_COMBINATION + Blockly.Yail.YAIL_LIST_CONSTRUCTOR + Blockly.Yail.YAIL_SPACER;
code = code + argument0 + Blockly.Yail.YAIL_SPACER + argument1 + Blockly.Yail.YAIL_SPACER + argument2 + Blockly.Yail.YAIL_CLOSE_COMBINATION;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_QUOTE + Blockly.Yail.YAIL_OPEN_COMBINATION;
code = code + "any list any" + Blockly.Yail.YAIL_CLOSE_COMBINATION + Blockly.Yail.YAIL_SPACER;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_DOUBLE_QUOTE + "lookup in pairs" + Blockly.Yail.YAIL_DOUBLE_QUOTE + Blockly.Yail.YAIL_CLOSE_COMBINATION;
return [ code, Blockly.Yail.ORDER_ATOMIC ];
};

Blockly.Yail['lists_join_with_separator'] = function() {
// Joins list items into a string separated by specified separator
var argument0 = Blockly.Yail.valueToCode(this, 'SEPARATOR', Blockly.Yail.ORDER_NONE) || "\"\"";
var argument1 = Blockly.Yail.valueToCode(this, 'LIST', Blockly.Yail.ORDER_NONE) || Blockly.Yail.emptyListCode;
var code = Blockly.Yail.YAIL_CALL_YAIL_PRIMITIVE + "yail-list-join-with-separator" + Blockly.Yail.YAIL_SPACER;
code = code + Blockly.Yail.YAIL_OPEN_COMBINATION + Blockly.Yail.YAIL_LIST_CONSTRUCTOR + Blockly.Yail.YAIL_SPACER;
code = code + argument1 + Blockly.Yail.YAIL_SPACER;
code = code + argument0 + Blockly.Yail.YAIL_CLOSE_COMBINATION;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_QUOTE;
code = code + Blockly.Yail.YAIL_OPEN_COMBINATION + "list" + Blockly.Yail.YAIL_SPACER + "text" + Blockly.Yail.YAIL_CLOSE_COMBINATION;
code = code + Blockly.Yail.YAIL_SPACER + Blockly.Yail.YAIL_DOUBLE_QUOTE + "join with separator" + Blockly.Yail.YAIL_DOUBLE_QUOTE + Blockly.Yail.YAIL_CLOSE_COMBINATION;
return [ code, Blockly.Yail.ORDER_ATOMIC ];
};
@@ -901,6 +901,14 @@ Blockly.Msg.en.switch_language_to_english = {
Blockly.Msg.LANG_LISTS_LOOKUP_IN_PAIRS_INPUT = 'look up in pairs key %1 pairs %2 notFound %3';
Blockly.Msg.LANG_LISTS_LOOKUP_IN_PAIRS_TOOLTIP = 'Returns the value associated with the key in the list of pairs';

// Join With Separator block
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_HELPURL = '/reference/blocks/lists.html#joinwithseparator';
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_TITLE = 'join with separator';
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_SEPARATOR = 'separator';
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_LIST = 'list';
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_INPUT = 'join items using separator %1 list %2';
Blockly.Msg.LANG_LISTS_JOIN_WITH_SEPARATOR_TOOLTIP = 'Returns text with list elements joined with separator';

/*Blockly.Msg.LANG_LISTS_INDEX_OF_HELPURL = 'http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Farsubex.htm';
Blockly.Msg.LANG_LISTS_INDEX_OF_TITLE_FIND = 'find';
Blockly.Msg.LANG_LISTS_INDEX_OF_INPUT_OCCURRENCE = 'occurrence of item';
@@ -1777,7 +1777,10 @@ Blockly.Versioning.AllUpgradeMaps =
23: "noUpgrade",

// AI2: In BLOCKS_LANGUAGE_VERSION 24, added List Reverse Block
24: "noUpgrade"
24: "noUpgrade",

// AI2: In BLOCKS_LANGUAGE_VERSION 25, added Join With Separator Block
25: "noUpgrade"


}, // End Language upgraders
@@ -74,7 +74,11 @@ public void testControlsEvalButIgnore() throws Exception {
assertEquals("true", result.toString());
}


public void testListsJoinWithSeparator() throws Exception {
String result = BlocklyTestUtils.generatorTest(
testpath + "/tests/com/google/appinventor/generators_unit/listsJoinWithSeparatorTest.js");
assertEquals("true", result.toString());
}

// add more unit tests here

@@ -0,0 +1,92 @@
// Copyright 2011-2013 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

/**
* Unit test for "make a list" block Yail generator
*
* Author: Hal Abelson (hal@mit.edu)
*/

// This file runs a unit test for block Yail generation. It generates the
// Yail for a block and checks wheither that contains the expected Yail
// (modulo whitespace). This file illustrates how to test the "make a list"
// block (in the verison where there are no arguments). Use this file (minus the
// comments), as a template for creating other generator unit tests.

// You can insert the test into
// blocklyeditor/tests/com/google/appinventor/blocklyeditor/BlocklyCodeGeneratorTest.java
// to include it in the suite of unit tests.

// You can also run this single test from the command line in the
// appinventor directory by executing the command
// phantomJS blocklyeditor/tests/com/google/appinventor/generators_unit/listsCreateWithTest.js

// To create a generator test, you need to define four values:

// (1) expected: the correct yail string for the block with all slots empty
// delayedGenerator: The block Yail generation function (delayed)
// blockName: name of the block
// doesReturn: true if the block returns a value, false otherwise

// (2) We pass the generator function delayed, because the symbol Blockly
// is not defined when the required page is loaded, but it _will_ be defined after
// load, which is why we can force the value inside page.evaluate
// evaluation function. See the definition of generator_test_main_routine.js

// To find the correct value of expected, open the blocks pane, drag out the block
// and hightlight it (keep the sockets empty), then start the debugger and run in the console:

// bs = Blocklies['5629499534213120_Screen1']; // or whatever the right index is
// bs.Yail.lists_create_with.call(bs.selected);

// Alternatively, you can get the array of blocks on the screen with
// Blocklies["5066549580791808_Screen1"].mainWorkspace.getTopBlocks();

// Get the appropraite block, and then run
// Blockly.Yail.BlocktoCode1(block)


// (3) Whether or not the block returns a value

// (4) If the block uses a dropdown to specify the operator,
// pass in the tag for that operator (as defined by the generator).
// If no dropdown, pass in false

////////////////////////////////////////
// These four variables are all you need to define to create a test
////////////////////////////////////////

var expected =
"(call-yail-primitive yail-list-join-with-separator (*list-for-runtime* (call-yail-primitive make-yail-list (*list-for-runtime* ) '() \"make a list\") \"\") '(list text) \"join with separator\")";


var delayedGenerator = function () { return Blockly.Yail.lists_join_with_separator; } ;

var blockName = 'lists_join_with_separator';

var doesReturn = true;

var dropdownOp = false;




////////////////////////////////////////
// The rest of this page is common to all tests.
////////////////////////////////////////

// PhantomJS page object to open and load an URL - unfortunately we need to fully load Blockly
var page = require('webpage').create();
// Some debugging from PhantomJS
page.onConsoleMessage = function (msg) { console.log(msg); };
page.onError = function (msg, trace) {
console.log(msg);
trace.forEach(function(item) {
console.log(' ', item.file, ':', item.line);
});
};

var mainTest = require('./generator_test_mainRoutine.js');
mainTest.execute();

@@ -1904,6 +1904,7 @@ Block name Kawa implementation
- is list? (yail-list? object)
- is empty? (yail-list-empty? yail-list)
- lookup in pairs (yail-alist-lookup key yail-list-of-pairs default)
- join with separator (yail-list-join-with-separator yail-list separator)

Lists in App Inventor are implemented as "Yail lists". A Yail list is
a Java pair whose car is a distinguished token
@@ -2331,7 +2332,11 @@ list, use the make-yail-list constructor with no arguments.
(and (yail-list? candidate-pair)
(= (length (yail-list-contents candidate-pair)) 2)))


;;; Joins list elements into a string separated by separator
;;; Important to convert yail-list to yail-list-contents so that *list*
;;; is not included as first string.
(define (yail-list-join-with-separator yail-list separator)
(join-strings (yail-list-contents yail-list) separator))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -448,8 +448,10 @@ private YaVersion() {
// - BLOCKS_LANGUAGE_VERSION was incremented to 24
// For YOUNG_ANDROID_VERSION 180:
// - VIDEOPLAYER_COMPONENT_VERSION was incremented to 6
// For YOUNG_ANDROID_VERSION 181:
// - BLOCKS_LANGUAGE_VERSION was incremented to 25

public static final int YOUNG_ANDROID_VERSION = 180;
public static final int YOUNG_ANDROID_VERSION = 181;

// ............................... Blocks Language Version Number ...............................

@@ -517,8 +519,10 @@ private YaVersion() {
// - Bitwise and, ior, and xor blocks were added.
// For BLOCKS_LANGUAGE_VERSION 24:
// - List reverse block was added.
// For BLOCKS_LANGUAGE_VERSION 25:
// - List join with separator block was added.

public static final int BLOCKS_LANGUAGE_VERSION = 24;
public static final int BLOCKS_LANGUAGE_VERSION = 25;

// ................................. Component Version Numbers ..................................

Binary file not shown.
@@ -226,6 +226,7 @@ <h1 class="node-title">
<li><a href="#listfromcsvrow">list from csv row</a></li>
<li><a href="#listfromcsvtable">list from csv table</a></li>
<li><a href="#lookupinpairs">lookup in pairs</a></li>
<li><a href="#joinwithseparator">join with separator</a></li>
</ul><h4><em>Need additional help understanding lists? Check out <a href="../concepts/lists.html">making lists</a> on the Concepts page.</em></h4>
<h3 id="emptylist">create empty list</h3>
<p><img src="images/lists/emptylist.png" /></p>
@@ -307,6 +308,10 @@ <h3 id="lookupinpairs">lookup in pairs</h3>
element. For example, if the list is ((a apple) (d dragon) (b boxcar) (cat 100)) then looking up 'b' will return 'boxcar'.<br />
If there is no such pair in the list, then the <em>lookup in pairs</em> will return the <em>notFound</em> result. If pairs is not a list of<br />
pairs, then the operation will signal an error.</p>
<h3 id="joinwithseparator">join with separator</h3>
<p><img src="images/lists/joinwithseparator.png" /></p>
<p>Joins all elements in the specified list by the specified separator, producing text as a result.<br />
By default, the separator is an empty string ("")</p>
</div></div></div> </div>


0 comments on commit ceb27bf

Please sign in to comment.
You can’t perform that action at this time.