Skip to content

Commit b67b10a

Browse files
feat: support no-arg method placeholders and add plugin activation guide
1 parent 082e06a commit b67b10a

11 files changed

Lines changed: 450 additions & 20 deletions

File tree

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ BPJ.println("Bienvenido {usuario.name}", this);
99

1010
## What It Is For
1111

12-
- Build readable messages with placeholders (`{name}`, `{product.value}`, `{final}`).
12+
- Build readable messages with placeholders (`{name}`, `{product.value}`, `{persona.getName()}`, `{final}`).
1313
- Return interpolated `String` values with `BPJ.format(...)`.
1414
- Print interpolated text with `BPJ.print(...)` and `BPJ.println(...)`.
1515
- Use Maven or Gradle build-time transformation so one-argument BPJ calls can work in regular Java code.
@@ -79,11 +79,15 @@ Legacy fallback (`buildscript` + `apply plugin`) is still supported.
7979

8080
## Usage
8181

82+
Activation guide:
83+
- `docs/PLUGIN_ACTIVATION_GUIDE.md`
84+
8285
### Print
8386

8487
```java
8588
BPJ.println("Hola {name}");
8689
BPJ.print("Valor del producto: {product.value}");
90+
BPJ.print("Nombre: {persona.getName()}");
8791
```
8892

8993
### Return a String

bpj-gradle-plugin/src/main/java/io/github/bpj/gradle/transform/BpjSourceTransformer.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ public final class BpjSourceTransformer {
4949
"printHighlighted",
5050
"printlnHighlighted"
5151
);
52-
private static final Pattern PLACEHOLDER_PATTERN =
53-
Pattern.compile("\\{\\s*([a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*)\\s*\\}");
54-
private static final Pattern PLACEHOLDER_EXPRESSION_PATTERN =
55-
Pattern.compile("^[a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*$");
52+
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(
53+
"\\{\\s*([a-zA-Z_$][\\w$]*(?:\\.(?:[a-zA-Z_$][\\w$]*|[a-zA-Z_$][\\w$]*\\(\\)))*)\\s*\\}"
54+
);
55+
private static final Pattern PLACEHOLDER_EXPRESSION_PATTERN = Pattern.compile(
56+
"^[a-zA-Z_$][\\w$]*(?:\\.(?:[a-zA-Z_$][\\w$]*|[a-zA-Z_$][\\w$]*\\(\\)))*$"
57+
);
5658
private static final Pattern BRACED_TOKEN_PATTERN = Pattern.compile("\\{([^{}]*)\\}");
5759
private static final String ESCAPED_OPEN_TOKEN = "\u0001BPJ_OPEN\u0001";
5860
private static final String ESCAPED_CLOSE_TOKEN = "\u0001BPJ_CLOSE\u0001";
@@ -296,7 +298,7 @@ private IllegalArgumentException invalidPlaceholderException(
296298

297299
String message = "Invalid BPJ placeholder(s) " + invalid
298300
+ " at " + location
299-
+ ". Allowed syntax: {name} or {object.field}. "
301+
+ ". Allowed syntax: {name}, {object.field}, or {object.getField()}. "
300302
+ "Use double braces to escape literals: {{ and }}.";
301303
return new IllegalArgumentException(message);
302304
}

bpj-gradle-plugin/src/test/java/io/github/bpj/gradle/transform/BpjSourceTransformerTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,26 @@ record User(String name, long id) {}
4646
assertTrue(result.source().contains("java.util.Map.of(\"user\", user)"));
4747
}
4848

49+
@Test
50+
void shouldInjectOnlyRootVariableForMethodPlaceholder() {
51+
String source = """
52+
import io.github.bpj.BPJ;
53+
class Demo {
54+
void run(User user) {
55+
BPJ.println("Welcome {user.getName()}");
56+
}
57+
static class User {
58+
String getName() { return "A"; }
59+
}
60+
}
61+
""";
62+
63+
BpjSourceTransformer.TransformationResult result = transform(source);
64+
65+
assertEquals(1, result.replacements());
66+
assertTrue(result.source().contains("java.util.Map.of(\"user\", user)"));
67+
}
68+
4969
@Test
5070
void shouldSupportStaticImportCalls() {
5171
String source = """
@@ -124,6 +144,26 @@ void run(String user) {
124144
assertTrue(exception.getMessage().contains("Demo.java:4"));
125145
}
126146

147+
@Test
148+
void shouldFailWhenPlaceholderUsesMethodArguments() {
149+
String source = """
150+
import io.github.bpj.BPJ;
151+
class Demo {
152+
void run(String name) {
153+
BPJ.println("Welcome {name.substring(1)}");
154+
}
155+
}
156+
""";
157+
158+
IllegalArgumentException exception = assertThrows(
159+
IllegalArgumentException.class,
160+
() -> transform(source)
161+
);
162+
163+
assertTrue(exception.getMessage().contains("Invalid BPJ placeholder(s)"));
164+
assertTrue(exception.getMessage().contains("{name.substring(1)}"));
165+
}
166+
127167
@Test
128168
void shouldFailOnUnresolvedRootsWhenEnabled() {
129169
String source = """

bpj-maven-plugin/src/main/java/io/github/bpj/maven/transform/BpjSourceTransformer.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,12 @@ public final class BpjSourceTransformer {
5959
"printHighlighted",
6060
"printlnHighlighted"
6161
);
62-
private static final Pattern PLACEHOLDER_PATTERN =
63-
Pattern.compile("\\{\\s*([a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*)\\s*\\}");
64-
private static final Pattern PLACEHOLDER_EXPRESSION_PATTERN =
65-
Pattern.compile("^[a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*$");
62+
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(
63+
"\\{\\s*([a-zA-Z_$][\\w$]*(?:\\.(?:[a-zA-Z_$][\\w$]*|[a-zA-Z_$][\\w$]*\\(\\)))*)\\s*\\}"
64+
);
65+
private static final Pattern PLACEHOLDER_EXPRESSION_PATTERN = Pattern.compile(
66+
"^[a-zA-Z_$][\\w$]*(?:\\.(?:[a-zA-Z_$][\\w$]*|[a-zA-Z_$][\\w$]*\\(\\)))*$"
67+
);
6668
private static final Pattern BRACED_TOKEN_PATTERN = Pattern.compile("\\{([^{}]*)\\}");
6769
private static final String ESCAPED_OPEN_TOKEN = "\u0001BPJ_OPEN\u0001";
6870
private static final String ESCAPED_CLOSE_TOKEN = "\u0001BPJ_CLOSE\u0001";
@@ -306,7 +308,7 @@ private IllegalArgumentException invalidPlaceholderException(
306308

307309
String message = "Invalid BPJ placeholder(s) " + invalid
308310
+ " at " + location
309-
+ ". Allowed syntax: {name} or {object.field}. "
311+
+ ". Allowed syntax: {name}, {object.field}, or {object.getField()}. "
310312
+ "Use double braces to escape literals: {{ and }}.";
311313
return new IllegalArgumentException(message);
312314
}

bpj-maven-plugin/src/test/java/io/github/bpj/maven/transform/BpjSourceTransformerTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,26 @@ record User(String name, long id) {}
4646
assertTrue(result.source().contains("java.util.Map.of(\"user\", user)"));
4747
}
4848

49+
@Test
50+
void shouldInjectOnlyRootVariableForMethodPlaceholder() {
51+
String source = """
52+
import io.github.bpj.BPJ;
53+
class Demo {
54+
void run(User user) {
55+
BPJ.println("Welcome {user.getName()}");
56+
}
57+
static class User {
58+
String getName() { return "A"; }
59+
}
60+
}
61+
""";
62+
63+
BpjSourceTransformer.TransformationResult result = transform(source);
64+
65+
assertEquals(1, result.replacements());
66+
assertTrue(result.source().contains("java.util.Map.of(\"user\", user)"));
67+
}
68+
4969
@Test
5070
void shouldSupportStaticImportCalls() {
5171
String source = """
@@ -157,6 +177,26 @@ void run(String user) {
157177
assertTrue(exception.getMessage().contains("Demo.java:4"));
158178
}
159179

180+
@Test
181+
void shouldFailWhenPlaceholderUsesMethodArguments() {
182+
String source = """
183+
import io.github.bpj.BPJ;
184+
class Demo {
185+
void run(String name) {
186+
BPJ.println("Welcome {name.substring(1)}");
187+
}
188+
}
189+
""";
190+
191+
IllegalArgumentException exception = assertThrows(
192+
IllegalArgumentException.class,
193+
() -> transform(source)
194+
);
195+
196+
assertTrue(exception.getMessage().contains("Invalid BPJ placeholder(s)"));
197+
assertTrue(exception.getMessage().contains("{name.substring(1)}"));
198+
}
199+
160200
@Test
161201
void shouldFailOnUnresolvedRootsWhenEnabled() {
162202
String source = """

0 commit comments

Comments
 (0)