每天晚上,在“重新加载”(UTC时间00:00)之前15分钟,我都会发布一些声誉差异代码审查用户。示例输出为:
Mat's Mug vs. Simon Forsberg:2728差异。年:+3618。季度:+885。月:+648。周:-40。日期:+185。
下面的代码使用以下类/接口:
StackExchangeAPI
:包含用于进行Stack Exchange API请求。然后将结果解析为JSON并将其“抽取”并存储到Groovy对象中。DugaBot
:包含用于向聊天室发送消息的方法WebhookParameters
:有关在何处发送信息发送聊天消息(在哪个聊天室)此类在启动时(或重新加载任务时)创建,然后通过Grails中的cron触发器在该类上调用
run()
。关于此代码的任何评论,请感激。
此代码也可在Github上使用:Zomis / Duga。
class UserRepDiffTask implements Runnable {
private final StackExchangeAPI stackApi;
private final DugaBot chatBot;
private final String usersString;
private final String site;
private final WebhookParameters room;
public UserRepDiffTask(StackExchangeAPI stackApi, String room, DugaBot chatBot, String users, String site) {
this.stackApi = stackApi;
this.chatBot = chatBot;
this.usersString = users.replace(',', ';');
this.room = WebhookParameters.toRoom(room);
this.site = site;
}
@Override
public void run() {
try {
def result = stackApi.apiCall("users/" + usersString, site, "!23IYXA.sS8.otifg5Aq.2");
List users = result.items
if (users.size() != 2) {
throw new UnsupportedOperationException("Cannot check diff for anything other than two users");
}
def max = users.stream().max(Comparator.comparingInt({it.reputation})).get();
def min = users.stream().min(Comparator.comparingInt({it.reputation})).get();
StringBuilder str = new StringBuilder();
str.append(clearName(max.display_name) + " vs. " + clearName(min.display_name) + ": ");
str.append((int)max.reputation - (int)min.reputation);
str.append(" diff. ");
diffStr(str, max, min, "Year", {it.reputation_change_year});
diffStr(str, max, min, "Quarter", {it.reputation_change_quarter});
diffStr(str, max, min, "Month", {it.reputation_change_month});
diffStr(str, max, min, "Week", {it.reputation_change_week});
diffStr(str, max, min, "Day", {it.reputation_change_day});
chatBot.postSingle(room, str.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static String chatName(String displayName) {
return clearName(displayName).replace(" ", "");
}
public static String clearName(String displayName) {
while (displayName.contains("&#")) {
String replacement = displayName.substring(displayName.indexOf("&#") + 2);
try {
replacement = replacement.substring(0, replacement.indexOf(';'));
int ch = Integer.parseInt(replacement);
displayName = displayName.replaceFirst("&#\d+;", String.valueOf((char) ch));
} catch (RuntimeException ex) {
displayName = displayName.replaceFirst("&#", "");
}
}
return displayName;
}
private void diffStr(StringBuilder str, max, min, String string, ToIntFunction<?> function) {
str.append(string);
str.append(": ");
int maxValue = function.applyAsInt(max);
int minValue = function.applyAsInt(min);
int diff = maxValue - minValue;
str.append(diff > 0 ? "+" : "");
str.append(diff);
str.append(". ");
}
}
#1 楼
根本没有使用静态
chatName()
方法。摆脱它,因为它只会增加噪音。 为什么使用静态
clearName()
方法public
?使它成为private
和非静态的,或将其放置在其他类中,该类有责任进行此类清洁以获得明确的名称。 或者要问不同,像在
org.apache.commons.lang.StringEscapeUtils.unescapeHtml
中一样使用AnswerInvalidationCheck
有什么问题? StringBuilder
IMO如果您“知道”或可以缩小
StringBuilder
的结果容量,则应使用重载的构造函数,该构造函数初始容量作为参数。 我喜欢
StringBuillder
的流利方法。 IMO利用流利的方式使阅读代码变得更加容易。 进行字符串连接以为
append()
方法构建参数是有点奇怪。您为什么不只使用append()
方法? 一些垂直间距对于您的代码来说是很好的。它对相关代码进行分组,使其更具可读性。
def max = users.stream().max(Comparator.comparingInt({it.reputation})).get();
def min = users.stream().min(Comparator.comparingInt({it.reputation})).get();
StringBuilder str = new StringBuilder();
str.append(clearName(max.display_name) + " vs. " + clearName(min.display_name) + ": ");
str.append((int)max.reputation - (int)min.reputation);
str.append(" diff. ");
diffStr(str, max, min, "Year", {it.reputation_change_year});
diffStr(str, max, min, "Quarter", {it.reputation_change_quarter});
diffStr(str, max, min, "Month", {it.reputation_change_month});
#2 楼
首先,我将摆脱所有分号。他们在这里根本没有帮助。然后,我将为
usersString
和room
添加两个设置器,仅使用groovy提供的地图构造函数?您真的要阅读this.a = a;
this.b = b;
您应该保留一些实际重要的内容。简单的作业?让groovy为您做到这一点。
而不是这个
users.stream().max(Comparator.comparingInt({it.reputation})).get();
为什么不只使用它呢?
users.*reputation.max()
它更具可读性。同样适用于
min
。为什么还要等待API调用完成才能在有两个以上用户的情况下引发异常?创建类时,当usersString具有两个以上用户ID时,只需停止整个操作即可。
而不是此操作
diffStr(str, max, min, "Year", {it.reputation_change_year});
diffStr(str, max, min, "Quarter", {it.reputation_change_quarter});
diffStr(str, max, min, "Month", {it.reputation_change_month});
diffStr(str, max, min, "Week", {it.reputation_change_week});
diffStr(str, max, min, "Day", {it.reputation_change_day});
这样做可能更容易理解
['year', 'quarter', 'month', 'week', 'day'].each {
diffStr(str, max, min, it)
}
,然后像这样更改
diffStr
private diffStr(StringBuilder str, max, min, String duration) {
//Rest same
int maxValue = max."reputation_change_$duration"
int minValue = min."reputation_change_$duration"
//Rest same
}
我删除了
ToIntFunction
但您确实意识到实际上那里是Closure<Integer>
。无需在任何地方使用Java 8。并请注意,如果您不返回任何内容,则在指定访问权限的情况下就不需要空白。关于将
+
用于StringBuilder
以及使用Apache commons的部分已经讲过。请给我我的支持。最后,您知道了@CompileStatic。对?除非您在Groovy中使用动态事物,否则请在各处使用它。
评论
第一步是摆脱分号!大声笑。认真地说,我想做一些实验。您可以在用户列表中发布数据示例(在run()方法中)吗?您可以通过打印/登录users.inspect()获得示例。@EmmanuelRosa该数据可从Stack Exchange API获得,例如,请参见此API响应